File: u_sheets.sru
Size: 37387
Date: Mon, 07 Apr 2008 21:31:57 +0200
$PBExportHeader$u_sheets.sru
forward
global type u_sheets from u_base_container
end type
type st_outer from statictext within u_sheets
end type
type st_1 from statictext within u_sheets
end type
type uo_paint from u_paint within u_sheets
end type
type str_tabs from structure within u_sheets
end type
end forward

type str_tabs from structure
   string      classname
   dragobject     object
   string      displaytext
   integer     x
   integer     width
   boolean     active
   point    drawpoints[]
   rect     textrect
   boolean     isdynamic
   boolean     disabled
   powerobject    parentobject
   long     iconindex
   long     highlightindex
end type

global type u_sheets from u_base_container
integer width = 713
integer height = 536
boolean border = true
long backcolor = 268435456
boolean #resizeobjects = false
event type long ke_selectionchanging ( readonly integer oldindex,  readonly integer newindex )
event ke_selectionchanged ( readonly integer oldindex,  readonly integer newindex )
event ke_menuclicked ( )
event type boolean ke_canclosetab ( readonly integer ai_index )
event ke_maxtabsreached ( )
st_outer st_outer
st_1 st_1
uo_paint uo_paint
end type
global u_sheets u_sheets

type prototypes
FUNCTION long SelectClipRgn(ulong hdc, ulong hrgn) Library "GDI32.DLL"
FUNCTION ulong CreatePolygonRgn(ref POINT ppoint[], int count, int fillMode) Library "GDI32.DLL"
FUNCTION ulong SetCapture(ulong hwnd) LIBRARY "user32.dll"
FUNCTION ulong ReleaseCapture() LIBRARY "user32.dll"
end prototypes

type variables
Public:
long #MaxTabs = 10
boolean #BottomTabs
boolean #ShowBorder = TRUE
boolean #PopTabMenu = TRUE
boolean #UseTopMostParent
string #FontName = "Tahoma"
integer #FontSize = 11
boolean #UseThemeColors = TRUE
boolean #HighlightSelected = TRUE
boolean #BoldSelectedText = TRUE
boolean #ShowTabs = TRUE
long #TabAreaColor
long #TabLineColor = -1
long #TabStyle = 1
long #TabStartX = 0
private:
ulong iul_font, iul_fontbold
str_tabs istr_activetab
str_tabs istr_tabs[]
long il_angleleft = 5
long il_angleright = 5
long il_pad = 1
long il_xadjust = 8
boolean ib_suspendrefresh, ib_suspendevents
boolean ib_maxtabsreached
long HIGHLIGHT2 = RGB(230, 139, 44)
long HIGHLIGHT = RGB(255, 200, 60)
ulong iul_himl
long HOT_INDEX //rollover
boolean MouseCaptured
CONSTANT integer PAD_ICON = 20
end variables
forward prototypes
public subroutine of_drawtabs (ref n_svc_mgr anv_svc, readonly unsignedlong aul_hdc)
public subroutine of_updatepoints (ref n_svc_mgr anv_svc, readonly unsignedlong aul_hdc)
public subroutine of_refresh ()
protected subroutine of_createfont ()
protected subroutine of_cleanup ()
public subroutine of_bottomtabs (readonly boolean ab_set)
public subroutine of_addtabs (readonly string as_tabs[], readonly dragobject ado_children[])
public subroutine of_settabareacolor (readonly long al_color)
public subroutine of_settabstyle (readonly integer ai_style)
public function integer of_selecttab (readonly integer ai_index)
public function integer of_selecttab (readonly string as_text)
public function integer of_selecttab (readonly dragobject ado)
public subroutine of_closetab (readonly integer ai_index)
public function integer of_totalitems ()
public subroutine of_closealltabs ()
public subroutine of_showborder (readonly boolean ab_show)
public subroutine of_suspendrefresh ()
public subroutine of_resumerefresh ()
public subroutine of_settablinecolor (readonly long al_color)
public function dragobject of_getselectedtab ()
public function dragobject of_getobject (readonly string as_displaytext)
public function dragobject of_opentab (readonly string as_displaytext, readonly string as_classname)
public subroutine of_suspendevents (readonly boolean ab_suspend)
public function integer of_getobjectindex (readonly dragobject ado)
public function dragobject of_getobject (readonly integer ai_index)
public subroutine of_tabenable (readonly integer ai_index, readonly boolean ab_enable)
public function integer of_getselectedindex ()
public subroutine of_locktab (readonly boolean ab_disable)
protected function long of_indexfrompoint (readonly integer xpos, readonly integer ypos)
public subroutine of_showtabs (readonly boolean ab_set)
public subroutine of_closetab (readonly integer ai_index, readonly boolean ab_selectprevtab)
public function long of_gettabcount ()
public function integer of_addtab (readonly string as_displaytext, readonly dragobject ado_child)
public function boolean of_maxtabsreached ()
public function integer of_addtab (readonly string as_displaytext, readonly dragobject ado_child, readonly long al_iconindex)
public subroutine of_addtabs (readonly string as_tabs[], readonly dragobject ado_children[], readonly long al_iconindex[])
public function dragobject of_opentab (readonly string as_displaytext, readonly string as_classname, readonly long al_iconindex)
public subroutine of_closetab (readonly dragobject ado_object, readonly boolean ab_selectprevtab)
public subroutine of_closetab (readonly dragobject ado_object)
public subroutine of_setimagelist (readonly unsignedlong aul_himl)
end prototypes

event type long ke_selectionchanging(readonly integer oldindex, readonly integer newindex);RETURN Cret.SUCCESS
end event

event ke_selectionchanged(readonly integer oldindex, readonly integer newindex);//tab selection changed
end event

event ke_menuclicked();string ls_data

ls_data = STRING(Message.LongParm, "address")

of_Closetab(INTEGER(ls_data))
end event

event type boolean ke_canclosetab(readonly integer ai_index);RETURN TRUE
end event

event ke_maxtabsreached();//fired when max tabs reached
ib_maxtabsreached = TRUE
end event

public subroutine of_drawtabs (ref n_svc_mgr anv_svc, readonly unsignedlong aul_hdc);//no drawing if tabs not shown
IF NOT #ShowTabs THEN RETURN

long ll_count, n, ll_lastx, ll_activeindex
n_svc_theme lnv_theme
n_svc_imagelist lnv_img
n_svc_resource lnv_res
n_svc_color lnv_c
rect lstr_Rect
str_theme lstr_theme
long ll_pen, ll_oldpen, ll_color, ll_pencolor
long ll_penhighlight, ll_penhightlightcolor
long ll_penhighlight2, ll_penhightlightcolor2
long ll_penhighlight3, ll_penhightlightcolor3
long ll_backbrush, ll_oldbrush, ll_oldfont
long ll_padicony, ll_hidx
point lpt, lpt_h

//border
IF #ShowBorder THEN
   st_outer.BorderColor = #TabLineColor
END IF

ll_count = UPPERBOUND(istr_tabs)

//background
//anv_svc.of_LoadSvc(lnv_win32, CSvc.WIN32)
IF ll_count > 0 THEN
   ll_backbrush = uo_paint.CreateSolidBrush(#TabAreaColor)
ELSE
   ll_backbrush = uo_paint.CreateSolidBrush(uo_paint.GetSysColor(CWin32.COLOR_APPWORKSPACE))
END IF
uo_paint.Getclientrect(Handle(uo_paint), lstr_rect)
uo_paint.FillRect(aul_hdc, lstr_rect, ll_backbrush)
uo_paint.DeleteObject(ll_backbrush)

IF ll_count <= 0 THEN RETURN

IF #BottomTabs THEN
   ll_padicony = -1
ELSE
   ll_padicony = -//0
END IF

//update points
of_UpdatePoints(anv_svc, aul_hdc)
//font
uo_paint.SelectObject(aul_hdc, iul_font)
//theme
anv_svc.of_LoadSvc(lnv_theme, CSvc.THEME)
lstr_theme = lnv_theme.of_GetTheme()
//pen
ll_pencolor = #TabLineColor
ll_pen = uo_paint.Createpen(0, 1, ll_pencolor)
ll_oldpen = uo_paint.SelectObject(aul_hdc, ll_pen)

//inactive tab fill
//IF #GrayInactivePage THEN
// ll_color = uo_paint.GetSysColor(CWin32.COLOR_BTNFACE)
//ELSE
   ll_color = uo_paint.GetSysColor(CWin32.COLOR_WINDOW)
//END IF

ll_backbrush = uo_paint.CreateSolidBrush(ll_color)
ll_oldbrush = uo_paint.SelectObject(aul_hdc, ll_backbrush)

anv_svc.of_LoadSvc(lnv_c, CSvc.COLOR)

//draw inactive tabs first
FOR n = ll_count to 1 STEP -1
   IF istr_tabs[n].active THEN
      ll_activeindex = n
      CONTINUE
   END IF
   
   //polygon
   uo_paint.Polygon(aul_hdc, istr_tabs[n].drawpoints, UPPERBOUND(istr_tabs[n].drawpoints))
   
   ////////////////////////////////////////////////////
   //draw gradient
   ulong llrgn
   long z, ll
   rect rc
   point lstr_p[]
   
   lstr_p = istr_tabs[n].drawpoints
   ll = istr_tabs[n].highlightindex
   FOR z = 1 to ll
      lstr_p[z].px += 1
   NEXT
   ll += 1
   FOR z = ll to UPPERBOUND(lstr_p)
      lstr_p[z].px -= 1
   NEXT
   IF #BottomTabs THEN
      lstr_p[1].py += 1
   ELSE
      lstr_p[istr_tabs[n].highlightindex].py += 1
      lstr_p[istr_tabs[n].highlightindex + 1].py += 1
   END IF
   llrgn = CreatePolygonRgn(lstr_p, UPPERBOUND(lstr_p), 1)
   SelectClipRgn(aul_hdc, llrgn)
   rc.left = lstr_p[1].px
   rc.right = lstr_p[UPPERBOUND(lstr_p)].px
   IF #BottomTabs THEN
      rc.top = -35
      rc.bottom = 20
      IF HOT_INDEX = n THEN
         lnv_c.of_DrawGradient(aul_hdc, rc, lstr_theme.hotgradientend, lstr_theme.hotgradientstart, TRUE)
      ELSE
         lnv_c.of_DrawGradient(aul_hdc, rc, lstr_theme.toolbargradientend, CColor.WHITE, TRUE)
      END IF
   ELSE
      rc.top = 0
      rc.bottom = 55
      IF HOT_INDEX = n THEN
         lnv_c.of_DrawGradient(aul_hdc, rc, lstr_theme.hotgradientstart, lstr_theme.hotgradientend, TRUE)
      ELSE
         lnv_c.of_DrawGradient(aul_hdc, rc, CColor.WHITE, lstr_theme.toolbargradientend, TRUE)
      END IF
   END IF
   SelectClipRgn(aul_hdc, 0)
   uo_paint.DeleteObject(llrgn)
   ////////////////////////////////////////////////////  
   
   uo_paint.SetBkMode(aul_hdc, 1)
   
   //set font color
   IF istr_tabs[n].disabled THEN
      uo_paint.SetTextColor(aul_hdc, uo_paint.GetSysColor(CWin32.COLOR_GRAYTEXT))
   ELSE
      uo_paint.SetTextColor(aul_hdc, uo_paint.GetSysColor(CWin32.COLOR_BTNTEXT))
   END IF
   uo_paint.Drawtext(aul_hdc, istr_tabs[n].displaytext, LEN(istr_tabs[n].displaytext), istr_tabs[n].textrect, 0)

   //draw image
   IF istr_tabs[n].iconindex > 0 THEN
      //lazy load imagelist service
      IF iul_himl <= 0 THEN
         anv_svc.of_LoadSvc(lnv_res, CSvc.RESOURCE)
         iul_himl = lnv_res.of_GetStandardImageList16(anv_svc)
      END IF
      IF NOT ISVALID(lnv_img) THEN
         anv_svc.of_LoadSvc(lnv_img, CSvc.IMAGELIST)
      END IF
      
      lnv_img.of_Draw(iul_himl, istr_tabs[n].iconindex - 1, aul_hdc, istr_tabs[n].textrect.left - PAD_ICON, istr_tabs[n].textrect.top + ll_padicony, 1)
   END IF
   
   uo_paint.SetBkMode(aul_hdc, 0)
NEXT

//draw active
IF ll_activeindex < 1 THEN ll_activeindex = 1
n = ll_activeindex
//active tab fill
ll_backbrush = uo_paint.SelectObject(aul_hdc, ll_oldbrush)
uo_paint.DeleteObject(ll_backbrush)
ll_color = uo_paint.GetSysColor(CWin32.COLOR_WINDOW)
ll_backbrush = uo_paint.CreateSolidBrush(ll_color)
ll_oldbrush = uo_paint.SelectObject(aul_hdc, ll_backbrush)
//bold font
IF #BoldSelectedText THEN
   uo_paint.SelectObject(aul_hdc, iul_fontbold)
ELSE
   uo_paint.SelectObject(aul_hdc, iul_font)
END IF
uo_paint.Polygon(aul_hdc, istr_tabs[n].drawpoints, UPPERBOUND(istr_tabs[n].drawpoints))
uo_paint.Drawtext(aul_hdc, istr_tabs[n].displaytext, LEN(istr_tabs[n].displaytext), istr_tabs[n].textrect, 0)
uo_paint.SetBkMode(aul_hdc, 1)

//draw image
IF istr_tabs[n].iconindex > 0 THEN
   //lazy load imagelist service
   IF iul_himl <= 0 THEN
      anv_svc.of_LoadSvc(lnv_res, CSvc.RESOURCE)
      iul_himl = lnv_res.of_GetStandardImageList16(anv_svc)
   END IF
   IF NOT ISVALID(lnv_img) THEN
      anv_svc.of_LoadSvc(lnv_img, CSvc.IMAGELIST)
   END IF

   lnv_img.of_Draw(iul_himl, istr_tabs[n].iconindex - 1, aul_hdc, istr_tabs[n].textrect.left - PAD_ICON, istr_tabs[n].textrect.top + ll_padicony, 1)
END IF

uo_paint.SetBkMode(aul_hdc, 0)

//draw highlights
IF #HighlightSelected THEN
   //highlight
// ll_penhightlightcolor = lstr_theme.listviewline1hot //HIGHLIGHT
// ll_penhighlight = uo_paint.Createpen(0, 1, ll_penhightlightcolor)
   ll_penhightlightcolor2 = lstr_theme.listviewline2hot //HIGHLIGHT2
   ll_penhighlight2 = uo_paint.Createpen(0, 1, ll_penhightlightcolor2)
   ll_penhightlightcolor3 = lstr_theme.listviewline3hot //HIGHLIGHT2
   ll_penhighlight3 = uo_paint.Createpen(0, 1, ll_penhightlightcolor3)
   
   ll_hidx = istr_tabs[n].highlightindex
   //draw highlight 3
   uo_paint.SelectObject(aul_hdc, ll_penhighlight3)
   uo_paint.MoveToEx(aul_hdc, istr_tabs[n].drawpoints[ll_hidx].px , istr_tabs[n].drawpoints[ll_hidx].py, lpt_h)
   uo_paint.LineTo(aul_hdc, istr_tabs[n].drawpoints[ll_hidx + 1].px, istr_tabs[n].drawpoints[ll_hidx + 1].py)
   //draw highlight 2
   uo_paint.SelectObject(aul_hdc, ll_penhighlight2)
   IF #BottomTabs THEN
      uo_paint.MoveToEx(aul_hdc, istr_tabs[n].drawpoints[ll_hidx].px , istr_tabs[n].drawpoints[ll_hidx].py - 1, lpt_h)
      uo_paint.LineTo(aul_hdc, istr_tabs[n].drawpoints[ll_hidx + 1].px, istr_tabs[n].drawpoints[ll_hidx + 1].py - 1)
   ELSE
      uo_paint.MoveToEx(aul_hdc, istr_tabs[n].drawpoints[ll_hidx].px , istr_tabs[n].drawpoints[ll_hidx].py + 1, lpt_h)
      uo_paint.LineTo(aul_hdc, istr_tabs[n].drawpoints[ll_hidx + 1].px, istr_tabs[n].drawpoints[ll_hidx + 1].py + 1)
   END IF
END IF

uo_paint.SelectObject(aul_hdc, ll_pen)
//lines
integer li_pad
long ll_upper
IF #BottomTabs THEN
   li_pad = 1
ELSE
   li_pad = -1
END IF
ll_upper = UPPERBOUND(istr_tabs[n].drawpoints)
uo_paint.MoveToex(aul_hdc, 0, istr_tabs[n].drawpoints[1].py + li_pad, lpt)
uo_paint.LineTo(aul_hdc, istr_tabs[n].drawpoints[1].px + 1, istr_tabs[n].drawpoints[1].py + li_pad)
uo_paint.MoveToex(aul_hdc, istr_tabs[n].drawpoints[ll_upper].px, istr_tabs[n].drawpoints[ll_upper].py + li_pad, lpt)
uo_paint.LineTo(aul_hdc, lstr_rect.right - lstr_rect.left, istr_tabs[n].drawpoints[ll_upper].py + li_pad)
//clean-up
ll_backbrush = uo_paint.SelectObject(aul_hdc, ll_oldbrush)
uo_paint.DeleteObject(ll_backbrush)
ll_pen = uo_paint.SelectObject(aul_hdc, ll_oldpen)
uo_paint.DeleteObject(ll_pen)
//uo_paint.DeleteObject(ll_penhighlight)
uo_paint.DeleteObject(ll_penhighlight2)
uo_paint.DeleteObject(ll_penhighlight3)
end subroutine

public subroutine of_updatepoints (ref n_svc_mgr anv_svc, readonly unsignedlong aul_hdc);n_svc_win32 lnv_win32
n_svc_iif lnv_iif
integer li_height, li_x, li_lx, li_textlen, li_y
point lstr_draw[]
rect lstr_rect
tagsize lstr_size
long ll_count, n, ll_oldfont
long ll_x[], ll_y[], m, ll_upper
point lstr_p[]
boolean lb_adjustx

anv_svc.of_LoadSvc(lnv_win32, CSvc.WIN32)
anv_svc.of_LoadSvc(lnv_iif, CSvc.IIF)

li_height = UnitsToPixels(uo_paint.height, YUnitsToPixels!)
li_x = #TabStartX

ll_count = UPPERBOUND(istr_tabs)
FOR n = 1 to ll_count
   //if first page not active, move x
   IF n = 1 AND NOT istr_tabs[n].Active THEN
      li_x = #TabStartX + 2
   END IF

   li_lx = li_x
      
   istr_tabs[n].drawpoints = lstr_p
   
   istr_tabs[n].highlightindex = 2

   IF istr_tabs[n].Active AND #BoldSelectedText THEN
      lnv_win32.SelectObject(aul_hdc, iul_fontbold)
   ELSE
      lnv_win32.SelectObject(aul_hdc, iul_font)
   END IF
   
   lnv_win32.GetTextExtentPoint32(aul_hdc, istr_tabs[n].displaytext, LEN(istr_tabs[n].displaytext), lstr_size)
   li_textlen = lstr_size.cx
   
   //pad space for icon
   IF istr_tabs[n].iconindex > 0 THEN
      li_textlen += PAD_ICON //16 pixels plus 2 pixel pad
   END IF
   
   lnv_win32.GetClientRect(Handle(uo_paint), lstr_rect)

   IF #BottomTabs THEN
      li_y = -1
      CHOOSE CASE #TabStyle
         CASE 1
            lb_adjustx = TRUE
            istr_tabs[n].highlightindex = 2
            //map points
            ll_x = {0, &
                     8, &
                     -100, 8}
            ll_y = {0, &
                     li_height - (lnv_iif.of_iif(istr_tabs[n].Active, 2, 3)), &
                     0, &
                     (li_height - (lnv_iif.of_iif(istr_tabs[n].Active, 2, 3))) * -1}
         CASE 2
            lb_adjustx = TRUE
            istr_tabs[n].highlightindex = 4
            //map points
            ll_x = {0, &
                     0, &
                     1, 1, -100,  1, 1,   0}
            ll_y = {0, &
                     li_height - (lnv_iif.of_iif(istr_tabs[n].Active, 2, 3)), &
                     1, 1,    0, -1, -1, -18}
         CASE 3
            lb_adjustx = FALSE
            istr_tabs[n].highlightindex = 7
            //map points
            ll_x = {0, 4, 2, 14, 2, 2, 2, -100,  1,  1,   0,  2}
            ll_y = {0, 1, 1, 14, 1, 1, 1,    0, -1, -1, -15, -2}           
      END CHOOSE
      
      ll_upper = UPPERBOUND(ll_x)
      FOR m = 1 to ll_upper
         IF ll_x[m] = -100 THEN
            li_x += li_textlen + (il_pad)// * 2)
         ELSE
            li_x += ll_x[m]
         END IF
         li_y += ll_y[m]
         istr_tabs[n].drawpoints[m].px = li_x
         istr_tabs[n].drawpoints[m].py = li_y
      NEXT
      
      IF lb_adjustx THEN
         IF NOT istr_tabs[n].Active THEN
            IF n < ll_count THEN
               IF NOT istr_tabs[n + 1].Active THEN
                  li_x += 4
               ELSE
                  li_x += 2
               END IF
            ELSE
               li_x += 4
            END IF
         ELSE
            IF n < ll_count THEN
               li_x += 2
            END IF
         END IF
      END IF
   ELSE
      CHOOSE CASE #TabStyle
         CASE 1
            li_y = 20
            lb_adjustx = TRUE
            istr_tabs[n].highlightindex = 2
            //map points
            ll_x = {0, &
                     8, &
                     -100, 8}
            ll_y = {0, &
                     -1 * (li_height - (lnv_iif.of_iif(istr_tabs[n].Active, 2, 3))), &
                     0, &
                     li_height - (lnv_iif.of_iif(istr_tabs[n].Active, 2, 3))}
         CASE 2
            li_y = 20
            lb_adjustx = TRUE
            istr_tabs[n].highlightindex = 4
            //map points
            ll_x = {0, &
                     0, &
                     1, 1, -100,  1, 1,   0}
            ll_y = {0, &
                     -1 * (li_height - (lnv_iif.of_iif(istr_tabs[n].Active, 2, 3))), &
                     -1, -1,    0, 1, 1, 18}          
         CASE 3
            li_y = 20
            lb_adjustx = FALSE
            istr_tabs[n].highlightindex = 7
            //map points
            ll_x = {0,  4,  2,  14,  2,  2,  2, -100, 1, 1, 0,  2}
            ll_y = {0, -1, -1, -14, -1, -1, -1,    0, 1, 1, 15, 2}            
         END CHOOSE


         ll_upper = UPPERBOUND(ll_x)
         FOR m = 1 to ll_upper
            IF ll_x[m] = -100 THEN
               li_x += li_textlen + (il_pad)// * 2)
            ELSE
               li_x += ll_x[m]
            END IF
            li_y += ll_y[m]
            istr_tabs[n].drawpoints[m].px = li_x
            istr_tabs[n].drawpoints[m].py = li_y
         NEXT
         
         IF lb_adjustx THEN
            IF NOT istr_tabs[n].Active THEN
               IF n < ll_count THEN
                  IF NOT istr_tabs[n + 1].Active THEN
                     li_x += 4
                  ELSE
                     li_x += 2
                  END IF
               ELSE
                  li_x += 4
               END IF
            ELSE
               IF n < ll_count THEN
                  li_x += 2
               END IF
            END IF
         END IF
   END IF
   
   istr_tabs[n].textrect.left = li_lx + il_pad + il_angleleft
   istr_tabs[n].textrect.right = li_textlen + il_pad + li_lx + il_angleright + il_angleleft

   //pad space for icon
   IF istr_tabs[n].iconindex > 0 THEN
      istr_tabs[n].textrect.left += PAD_ICON
      istr_tabs[n].textrect.right += PAD_ICON
   END IF
   
   IF #BottomTabs THEN
      istr_tabs[n].textrect.top = 2
      istr_tabs[n].textrect.bottom = li_height - 2
   ELSE
      istr_tabs[n].textrect.top = 3
      istr_tabs[n].textrect.bottom = li_height - 1
   END IF
   
   //adjust
   li_x -= il_xadjust
NEXT
end subroutine

public subroutine of_refresh ();IF ib_suspendrefresh THEN RETURN
//do posts
//Yield() 
st_outer.SetRedraw(TRUE)
this.TriggerEvent("resize")
IF ISVALID(istr_activetab.Object) THEN &
   istr_activetab.Object.BringToTop = TRUE
uo_paint.BringToTop = TRUE
uo_paint.SetRedraw(TRUE)
end subroutine

protected subroutine of_createfont ();LogFont lstr_Lf
uLong lul_Font
n_svc_mgr lnv_svc
n_svc_win32 lnv_win32
n_svc_iif lnv_iif

lnv_svc.of_loadsvc(lnv_win32, CSvc.WIN32)
lnv_svc.of_loadsvc(lnv_iif, CSvc.IIF)

lstr_Lf.lffacename = #FontName
lstr_Lf.lfweight = 400
lstr_Lf.lfheight = #FontSize * -1
lstr_Lf.lfPitchAndFamily = '1'
lstr_Lf.lfClipPrecision = Char(2)
lstr_Lf.lfOutPrecision = Char(1)
lstr_Lf.lfQuality = Char(1)
lstr_Lf.lfCharset = Char(1)

IF iul_font <> 0 THEN &
   lnv_win32.DeleteObject(iul_font)
IF iul_fontbold <> 0 THEN &
   lnv_win32.DeleteObject(iul_font)

iul_font = lnv_win32.CreateFontIndirect( lstr_Lf )
lstr_Lf.lfweight = 700
iul_fontbold = lnv_win32.CreateFontIndirect( lstr_Lf )
end subroutine

protected subroutine of_cleanup ();n_svc_mgr lnv_svc
n_svc_win32 lnv_win32

lnv_svc.of_LoadSvc(lnv_win32, CSvc.WIN32)
lnv_win32.DeleteObject(iul_font)
lnv_win32.DeleteObject(iul_fontbold)
end subroutine

public subroutine of_bottomtabs (readonly boolean ab_set);#BottomTabs = ab_set
TriggerEvent("resize")
of_Refresh()
end subroutine

public subroutine of_addtabs (readonly string as_tabs[], readonly dragobject ado_children[]);long ll_iconindex[]

ll_iconindex[UPPERBOUND(as_tabs)] = 0

of_AddTabs(as_tabs, ado_children, ll_iconindex)
end subroutine

public subroutine of_settabareacolor (readonly long al_color);#TabAreaColor = al_color

n_svc_mgr lnv_svc

IF #UseThemeColors THEN
   n_svc_theme lnv_t
   str_theme lstr
   
   lnv_svc.of_LoadSvc(lnv_t, CSvc.THEME)
   lstr = lnv_t.of_GetTheme()
   #TabAreaColor = lstr.window
ELSE
   IF al_color = 0 THEN
      n_svc_win32 lnv_win32
      
      lnv_svc.of_LoadSvc(lnv_win32, CSvc.WIN32)
      #TabAreaColor = lnv_win32.GetSysColor(CWin32.COLOR_BTNFACE)
   END IF
END IF
of_Refresh()
end subroutine

public subroutine of_settabstyle (readonly integer ai_style);#TabStyle = ai_style

CHOOSE CASE #TabStyle
   CASE 1 //excel style
      il_angleleft = 8
      il_angleright = 8
      il_pad = 1
      il_xadjust = 8
   CASE 2 //tab style
      il_angleleft = 0
      il_angleright = 0
      il_pad = 8
      il_xadjust = 2    
   CASE 3 //VS 2005 style
      il_angleleft = 19
      il_angleright = 0
      il_pad = 8
      il_xadjust = 20
END CHOOSE

of_Refresh()
end subroutine

public function integer of_selecttab (readonly integer ai_index);long ll_count, n
integer li_oldindex

ll_count = UPPERBOUND(istr_tabs)

IF ai_index > ll_count THEN RETURN CRet.FAILURE

FOR n = 1 to ll_count
   IF istr_tabs[n].Active THEN
      li_oldindex = n
      EXIT
   END IF
NEXT

IF li_oldindex = ai_index THEN RETURN CRet.NO_ACTION

IF NOT ib_suspendevents THEN
   IF EVENT ke_selectionchanging(li_oldindex, ai_index) &
         = CRet.FAILURE THEN RETURN Cret.FAILURE
END IF
      
FOR n = 1 to ll_count
   IF n = ai_index THEN
      istr_tabs[n].Active = TRUE
      istr_tabs[n].Object.Visible = TRUE
      istr_activetab = istr_tabs[n]
   ELSE
      istr_tabs[n].Active = FALSE
//    istr_tabs[n].Object.Visible = FALSE
   END IF
NEXT

of_Refresh()

//now hide inactive
//second loop to prevent flickering
FOR n = 1 to ll_count
   IF NOT istr_tabs[n].Active THEN
      IF istr_tabs[n].Object.Visible THEN &
         istr_tabs[n].Object.Visible = FALSE
   END IF
NEXT

IF NOT ib_suspendevents THEN
   EVENT ke_selectionchanged(li_oldindex, ai_index)
END IF

istr_activetab.Object.SetFocus()

RETURN CRet.SUCCESS
end function

public function integer of_selecttab (readonly string as_text);long ll_count, n
boolean lb_found

ll_count = UPPERBOUND(istr_tabs)
FOR n = 1 to ll_count
   IF lower(istr_tabs[n].DisplayText) = lower(as_text) THEN
      lb_found = TRUE
      EXIT
   END IF
NEXT

IF NOT lb_found THEN RETURN Cret.FAILURE

RETURN of_selecttab(n)
end function

public function integer of_selecttab (readonly dragobject ado);long ll_count, n
boolean lb_found

ll_count = UPPERBOUND(istr_tabs)
FOR n = 1 to ll_count
   IF istr_tabs[n].Object = ado THEN
      lb_found = TRUE
      EXIT
   END IF
NEXT

IF NOT lb_found THEN RETURN Cret.FAILURE

RETURN of_selecttab(n)
end function

public subroutine of_closetab (readonly integer ai_index);of_CloseTab(ai_index, TRUE)
end subroutine

public function integer of_totalitems ();RETURN UPPERBOUND(istr_tabs)
end function

public subroutine of_closealltabs ();long ll_count, n

ll_count = UPPERBOUND(istr_tabs)
of_SelectTab(1)
of_SuspendRefresh()
FOR n = ll_count to 1 STEP -1
   of_CloseTab(n, FALSE)
NEXT
of_ResumeRefresh()

end subroutine

public subroutine of_showborder (readonly boolean ab_show);#ShowBorder = ab_show
st_outer.BringToTop = FALSE
st_outer.Visible = #ShowBorder
of_Refresh()
end subroutine

public subroutine of_suspendrefresh ();ib_suspendrefresh = TRUE
end subroutine

public subroutine of_resumerefresh ();ib_suspendrefresh = FALSE
of_Refresh()
end subroutine

public subroutine of_settablinecolor (readonly long al_color);#TabLineColor = al_color

IF #TabLineColor = -1 THEN
   n_svc_mgr lnv_svc
   n_svc_theme lnv_theme
   
   lnv_svc.of_LoadSvc(lnv_theme, CSvc.THEME)
   #TabLineColor = lnv_theme.of_gettabbordercolor(lnv_svc)
END IF

st_outer.BorderColor = #TabLineColor
end subroutine

public function dragobject of_getselectedtab ();long ll_count, n
dragobject ldo

ll_count = UPPERBOUND(istr_tabs)
FOR n = 1 to ll_count
   IF istr_tabs[n].Active THEN
      ldo = istr_tabs[n].object
      EXIT
   END IF
NEXT

RETURN ldo
end function

public function dragobject of_getobject (readonly string as_displaytext);long ll_count, n
boolean lb_found
dragobject ldo

ll_count = UPPERBOUND(istr_tabs)
FOR n = 1 to ll_count
   IF lower(istr_tabs[n].DisplayText) = lower(as_displaytext) THEN
      lb_found = TRUE
      EXIT
   END IF
NEXT

IF lb_found THEN
   ldo = istr_tabs[n].object
END IF

RETURN ldo
end function

public function dragobject of_opentab (readonly string as_displaytext, readonly string as_classname);RETURN of_OpenTab(as_displaytext, as_classname, 0)
end function

public subroutine of_suspendevents (readonly boolean ab_suspend);ib_suspendevents = ab_suspend
end subroutine

public function integer of_getobjectindex (readonly dragobject ado);long ll_count, n
boolean lb_found
dragobject ldo
integer li_index = -1

ll_count = UPPERBOUND(istr_tabs)
FOR n = 1 to ll_count
   IF istr_tabs[n].object = ado THEN
      lb_found = TRUE
      EXIT
   END IF
NEXT

IF lb_found THEN
   li_index = n
END IF

RETURN li_index
end function

public function dragobject of_getobject (readonly integer ai_index);long ll_count
boolean lb_found
dragobject ldo

ll_count = UPPERBOUND(istr_tabs)
IF ai_index <= ll_count THEN
   ldo = istr_tabs[ai_index].object
END IF

RETURN ldo
end function

public subroutine of_tabenable (readonly integer ai_index, readonly boolean ab_enable);IF ai_index > UPPERBOUND(istr_tabs) THEN RETURN

istr_tabs[ai_index].disabled = NOT ab_enable

of_Refresh()
end subroutine

public function integer of_getselectedindex ();long ll_count, n
long ll_ret

ll_ret = CRet.FAILURE

ll_count = UPPERBOUND(istr_tabs)
FOR n = 1 to ll_count
   IF istr_tabs[n].Active THEN
      ll_ret = n
      EXIT
   END IF
NEXT

RETURN ll_ret
end function

public subroutine of_locktab (readonly boolean ab_disable);long ll_count, n

ll_count = UPPERBOUND(istr_tabs)
FOR n = 1 to ll_count
   istr_tabs[n].disabled = ab_disable
NEXT

of_Refresh()
end subroutine

protected function long of_indexfrompoint (readonly integer xpos, readonly integer ypos);//find out if a tab was clicked
n_svc_mgr lnv_svc
n_svc_win32 lnv_win32
long ll_count, n
ulong lul_rgn
integer lix, liy

lix = UnitsToPixels(xpos, XUnitsToPixels!)
liy = UnitsToPixels(ypos, YUnitsToPixels!)

lnv_svc.of_LoadSvc(lnv_win32, CSvc.WIN32)
ll_count = UPPERBOUND(istr_tabs)
FOR n = 1 to ll_count
   //skip if disabled
   IF istr_tabs[n].disabled THEN CONTINUE
   lul_rgn = lnv_win32.CreatePolygonRgn(istr_tabs[n].drawpoints, UPPERBOUND(istr_tabs[n].drawpoints), 1)
   IF lnv_win32.PtInRegion(lul_rgn, lix, liy) <> 0 THEN
      uo_paint.DeleteObject(lul_rgn)
      RETURN n
   ELSE
      uo_paint.DeleteObject(lul_rgn)
   END IF
NEXT

RETURN CRet.FAILURE
end function

public subroutine of_showtabs (readonly boolean ab_set);uo_paint.Visible = ab_set
#ShowTabs = ab_set

IF #ShowTabs THEN
   uo_paint.BringToTop = TRUE
ELSE
   uo_paint.BringToTop = FALSE
END IF

of_Refresh()
end subroutine

public subroutine of_closetab (readonly integer ai_index, readonly boolean ab_selectprevtab);long ll_count, n, c
str_tabs lstr[], lstr_empty

//re-index
ll_count = UPPERBOUND(istr_tabs)

IF ai_index = 0 OR ai_index > ll_count THEN RETURN

FOR n = 1 to ll_count
   IF n <> ai_index THEN
      c ++
      lstr[c] = istr_tabs[n]
   ELSE
      IF istr_tabs[ai_index].Active THEN
         IF n > 1 AND n <= ll_count THEN
            istr_activetab = istr_tabs[n - 1]
         ELSE
            IF n = 1 AND n < ll_count THEN
               istr_activetab = istr_tabs[n + 1]
            ELSE
               istr_activetab = lstr_empty
            END IF
         END IF
      END IF
   END IF
NEXT

//hide & close
istr_tabs[ai_index].Object.Visible = FALSE
IF istr_tabs[ai_index].IsDynamic THEN
   //fire destructor
   istr_tabs[ai_index].Object.TriggerEvent("destructor")
   of_CloseUserObject(istr_tabs[ai_index].Object)
ELSE
   //return to parent
   SetParent(Handle(istr_tabs[ai_index].ParentObject), Handle(istr_tabs[ai_index].Object))
END IF

istr_tabs = lstr
IF ab_selectprevtab THEN &
   of_SelectTab(istr_activetab.DisplayText)

of_Refresh()
end subroutine

public function long of_gettabcount ();long ll_count, n, c


ll_count = UPPERBOUND(istr_tabs)
FOR n = 1 to ll_count
   IF ISVALID(istr_tabs[n].Object) THEN
      c ++
   END IF
NEXT

RETURN c
end function

public function integer of_addtab (readonly string as_displaytext, readonly dragobject ado_child);RETURN of_AddTab(as_displaytext, ado_child, 0)
end function

public function boolean of_maxtabsreached ();RETURN ib_maxtabsreached
end function

public function integer of_addtab (readonly string as_displaytext, readonly dragobject ado_child, readonly long al_iconindex);long ll

ib_maxtabsreached = FALSE

IF of_GetTabCount() = #MaxTabs THEN
   EVENT ke_maxtabsreached()
   RETURN Cret.FAILURE
END IF

ll = UPPERBOUND(istr_tabs) + 1
istr_tabs[ll].displaytext = as_displaytext
istr_tabs[ll].object = ado_child
istr_tabs[ll].parentobject = ado_child.GetParent()
istr_tabs[ll].iconindex = al_iconindex

IF ll = 1 THEN
   istr_tabs[ll].Active = TRUE
   istr_activetab = istr_tabs[ll]
ELSE
   ado_child.Visible = FALSE
END IF

SetParent(Handle(ado_child), Handle(this))

of_Refresh()

IF ll = 1 THEN &
   istr_tabs[ll].object.POST DYNAMIC Show()//Visible = TRUE

RETURN CRet.SUCCESS
end function

public subroutine of_addtabs (readonly string as_tabs[], readonly dragobject ado_children[], readonly long al_iconindex[]);str_tabs lstr[]
long ll_count, n

//clear tabs
istr_tabs = lstr
ll_count = UPPERBOUND(as_tabs)
of_Suspendrefresh()
FOR n = 1 to ll_count
   IF of_addTab(as_tabs[n], ado_children[n], al_iconindex[n]) = CRet.FAILURE THEN
      of_ResumeRefresh()
      EXIT
   END IF
NEXT
of_ResumeRefresh()
end subroutine

public function dragobject of_opentab (readonly string as_displaytext, readonly string as_classname, readonly long al_iconindex);long ll
dragobject ldo

ib_maxtabsreached = FALSE

IF of_GetTabCount() = #MaxTabs THEN
   EVENT ke_maxtabsreached()
   RETURN ldo
END IF

ll = UPPERBOUND(istr_tabs) + 1
istr_tabs[ll].displaytext = as_displaytext
istr_tabs[ll].IsDynamic = TRUE
istr_tabs[ll].iconindex = al_iconindex

IF of_OpenUserObject(istr_tabs[ll].object, as_classname) = CRet.SUCCESS THEN
   SetPointer(Hourglass!)
   IF ll = 1 THEN
      istr_tabs[ll].Active = TRUE
      istr_activetab = istr_tabs[ll]
   ELSE
      istr_tabs[ll].object.Visible = FALSE
   END IF
   
   of_Refresh()
   
   ldo = istr_tabs[ll].object
   
   IF ll = 1 THEN &
      istr_tabs[ll].object.DYNAMIC Show()//Visible = TRUE
ELSE
   //adjust index
   str_tabs lstr_tabs[]
   long ll_count, n
   
   ll_count = ll - 1
   FOR n = 1 to ll_count
      lstr_tabs[n] = istr_tabs[n]
   NEXT
   
   istr_tabs = lstr_tabs
   ll --
END IF

RETURN ldo
end function

public subroutine of_closetab (readonly dragobject ado_object, readonly boolean ab_selectprevtab);IF ISVALID(ado_object) THEN
   integer li_index
   
   li_index = of_GetObjectIndex(ado_object)
   
   IF li_index > 0 THEN
      of_CloseTab(li_index, ab_selectprevtab)
   END IF
END IF
end subroutine

public subroutine of_closetab (readonly dragobject ado_object);of_CloseTab(ado_object, FALSE)
end subroutine

public subroutine of_setimagelist (readonly unsignedlong aul_himl);iul_himl = aul_himl
end subroutine

on u_sheets.create
int iCurrent
call super::create
this.st_outer=create st_outer
this.st_1=create st_1
this.uo_paint=create uo_paint
iCurrent=UpperBound(this.Control)
this.Control[iCurrent+1]=this.st_outer
this.Control[iCurrent+2]=this.st_1
this.Control[iCurrent+3]=this.uo_paint
end on

on u_sheets.destroy
call super::destroy
destroy(this.st_outer)
destroy(this.st_1)
destroy(this.uo_paint)
end on

event ke_preopen;call super::ke_preopen;st_1.Visible = FALSE
this.Border = FALSE
of_SuspendRefresh()
of_CreateFont()
of_ShowTabs(#ShowTabs)
of_ShowBorder(#ShowBorder)
of_SetTabStyle(#TabStyle)
of_SetTabAreaColor(#TabAreaColor)
of_SetTabLineColor(#TabLineColor)
of_ResumeRefresh()
end event

event ke_resize;//overriden event
integer li_py
integer lix, liy, li_height

lix = PixelsToUnits(1, XPixelsTounits!)
liy = Pixelstounits(1, YPixelsTounits!)

IF #ShowTabs THEN
   IF #BottomTabs THEN
      IF uo_paint.X <> 0 OR &
         uo_paint.Y <> (newheight - uo_paint.height) THEN &
            uo_paint.Move(0, newheight - uo_paint.height)
      IF st_outer.X <> 0 OR &
         st_outer.Y <> 0 THEN &
            st_outer.Move(0, 0)
      li_py = liy + 1
   ELSE
      IF uo_paint.X <> 0 OR &
         uo_paint.Y <> 0 THEN &
            uo_paint.Move(0, 0)
   
      IF st_outer.X <> 0 OR &
         st_outer.Y <> (uo_paint.height - 4) THEN &
            st_outer.Move(0, uo_paint.height - 4)
      li_py = uo_paint.height
   END IF
   
   IF uo_paint.Width <> newwidth THEN &
      uo_paint.Resize(newwidth, uo_paint.height)
      
   IF st_outer.Width <> newwidth OR &
      st_outer.Height <> (newheight - uo_paint.height) + 4 THEN &
         st_outer.Resize(newwidth, (newheight - uo_paint.height) + 4)

   li_height = newheight - (uo_paint.height + liy)
   
   //border?
   IF NOT #ShowBorder THEN
      lix = 0
      IF li_py = liy THEN li_py = 0
   END IF
   
   IF ISVALID(istr_activetab.object) THEN
      IF istr_activetab.object.X <> lix OR &
         istr_activetab.object.Y <> li_py THEN &
            istr_activetab.object.Move(lix, li_py)
      IF istr_activetab.object.width <> newwidth OR &
         istr_activetab.object.height <> li_height THEN &
            istr_activetab.object.Resize(newwidth - (lix * 2), li_height)
   END IF
ELSE
   li_py = liy
   li_height = newheight
   
   IF NOT #ShowBorder THEN
      lix = 0
      IF li_py = liy THEN li_py = 0
   END IF
   
   IF st_outer.X <> 0 OR &
      st_outer.Y <> 0 THEN &
         st_outer.Move(0, 0)

   IF st_outer.Width <> newwidth OR &
      st_outer.Height <> (newheight)THEN &
         st_outer.Resize(newwidth, newheight)

   IF ISVALID(istr_activetab.object) THEN
      IF istr_activetab.object.X <> lix OR &
         istr_activetab.object.Y <> li_py THEN &
            istr_activetab.object.Move(lix, li_py)
      IF istr_activetab.object.width <> newwidth OR &
         istr_activetab.object.height <> li_height THEN &
            istr_activetab.object.Resize(newwidth - (lix * 2), li_height - (li_py * 2))
   END IF
END IF
end event

event resize;//overriden - always resize
IF sizetype = 1 THEN RETURN
EVENT ke_resize(width, height)

end event

event destructor;call super::destructor;n_svc_mgr lnv_svc
n_svc_win32 lnv_win32

of_CloseAllTabs()

lnv_svc.of_loadsvc(lnv_win32, CSvc.WIN32)
lnv_win32.DeleteObject(iul_font)
lnv_win32.DeleteObject(iul_fontbold)
end event

type st_outer from statictext within u_sheets
integer y = 544
integer width = 343
integer height = 52
integer textsize = -8
integer weight = 400
fontcharset fontcharset = ansi!
fontpitch fontpitch = variable!
fontfamily fontfamily = swiss!
string facename = "Tahoma"
long textcolor = 33554432
long backcolor = 268435456
boolean border = true
long bordercolor = 1073741824
boolean focusrectangle = false
end type

type st_1 from statictext within u_sheets
integer x = 165
integer y = 208
integer width = 343
integer height = 52
integer textsize = -8
integer weight = 700
fontcharset fontcharset = ansi!
fontpitch fontpitch = variable!
fontfamily fontfamily = swiss!
string facename = "Tahoma"
long textcolor = 1073741824
long backcolor = 268435456
string text = "Sheet Tabs"
alignment alignment = center!
boolean focusrectangle = false
end type

type uo_paint from u_paint within u_sheets
event ke_menuclicked ( )
integer width = 713
integer height = 80
integer taborder = 20
boolean bringtotop = true
boolean border = false
long backcolor = 1073741824
long #sizeorder = -1
end type

event ke_menuclicked();//
end event

on uo_paint.destroy
call u_paint::destroy
end on

event ke_paint;call super::ke_paint;parent.of_Drawtabs(anv_svc, hdc)
end event

event ke_clicked;call super::ke_clicked;long ll_index

ll_index = of_IndexFromPoint(xpos, ypos)

IF ll_index > 0 THEN of_SelectTab(ll_index)

RETURN AncestorReturnValue
end event

event ke_rbuttondown;call super::ke_rbuttondown;//can we pop?
IF NOT #PopTabMenu THEN RETURN AncestorReturnValue

long ll_index

ll_index = of_IndexFromPoint(xpos, ypos)

IF ll_index = Cret.FAILURE THEN RETURN AncestorReturnValue

//check if can close tab
IF NOT parent.EVENT ke_canclosetab(ll_index) THEN RETURN AncestorReturnValue

n_svc_mgr lnv_svc
n_svc_menu lnv_m
str_menuitem lstr[]

lnv_svc.of_LoadSvc(lnv_m, CSvc.MENU)

lstr[1].menutext = "Close Tab"
lstr[1].subscriber = parent
lstr[1].eventname = "ke_menuclicked"
lstr[1].data = STRING(ll_index)

window lw

lw = of_GetParentwindow(#UseTopMostParent)

lnv_m.of_createmenu(lstr, lw.PointerX(), lw.PointerY())

RETURN AncestorReturnValue
end event

event ke_mousemove;call super::ke_mousemove;long llt

IF xpos >= 0 AND xpos <= this.width AND ypos >= 0 AND ypos <= this.height THEN
   IF NOT MouseCaptured THEN
      SetCapture(Handle(this.uo_pbnicanvas))
      MouseCaptured = TRUE
   END IF
   
   llt = of_IndexFromPoint(xpos, ypos)
   IF HOT_INDEX <> llt THEN
      HOT_INDEX = llt
      of_Refresh()
   END IF
ELSE
   IF MouseCaptured THEN
      ReleaseCapture()
      MouseCaptured = FALSE
   END IF
   
   IF HOT_INDEX <> CRet.FAILURE THEN
      HOT_INDEX = CRet.FAILURE
      of_Refresh()
   END IF
END IF
end event