/////////////////////////////////////////////////////////////////////////////// // // IMPORTANT NOTICE // // The following open source license statement does not apply to any // entity in the Exception List published by FMSoft. // // For more information, please visit: // // https://www.fmsoft.cn/exception-list // ////////////////////////////////////////////////////////////////////////////// /* * This file is part of MiniGUI, a mature cross-platform windowing * and Graphics User Interface (GUI) support system for embedded systems * and smart IoT devices. * * Copyright (C) 2002~2022, Beijing FMSoft Technologies Co., Ltd. * Copyright (C) 1998~2002, WEI Yongming * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Or, * * As this program is a library, any link to this program must follow * GNU General Public License version 3 (GPLv3). If you cannot accept * GPLv3, you need to be licensed from FMSoft. * * If you have got a commercial license of this program, please use it * under the terms and conditions of the commercial license. * * For more information about the commercial license, please refer to * . */ /* ** scrollview.c: a scrollview control ** ** Create date: 2004/03/01 */ #include #include #include #include #include "common.h" #ifdef _MGCTRL_SCROLLVIEW #include "minigui.h" #include "gdi.h" #include "window.h" #include "ctrl/ctrlhelper.h" #include "ctrl/scrollview.h" #include "cliprect.h" #include "internals.h" #include "ctrlclass.h" #include "ctrlmisc.h" #include "scrolled.h" #include "scrollview_impl.h" /* ------------------------------------ svlist --------------------------- */ static PSVITEMDATA svlistItemAdd (PSVLIST psvlist, PSVITEMDATA preitem, PSVITEMDATA nextitem, PSVITEMINFO pii, int *idx) { PSVITEMDATA ci; int ret; ci = (PSVITEMDATA) malloc (sizeof(SVITEMDATA)); if (!ci) return NULL; if (pii) { if (pii->nItemHeight <= 0) ci->nItemHeight = psvlist->nDefItemHeight; else ci->nItemHeight = pii->nItemHeight; ((MgItem *)ci)->addData = pii->addData; } else { ci->nItemHeight = psvlist->nDefItemHeight; ((MgItem *)ci)->addData = 0; } ret = mglist_add_item ( (MgList *)psvlist, (MgItem *)ci, (MgItem *)preitem, (MgItem *)nextitem, pii->nItem, idx ); if (ret < 0) { free (ci); return NULL; } return ci; } static int svlistItemDel (PSVLIST psvlist, PSVITEMDATA pci) { mglist_del_item ((MgList *)psvlist, (MgItem *)pci); free (pci); return 0; } static void svlist_reset_content (HWND hWnd, PSVLIST psvlist) { PSVITEMDATA pci; while (!mglist_empty((MgList *)psvlist)) { pci = (PSVITEMDATA)mglist_first_item ((MgList *)psvlist); svlistItemDel (psvlist, pci); } ((MgList *)psvlist)->nTotalItemH = 0; } //FIXME, to be moved to listmodel.c static int isInItem (MgList *mglst, int mouseX, int mouseY, MgItem **pRet, int *item_y) { //PSVLIST psvlist = (PSVLIST)mglst; int ret = 0; PSVITEMDATA pci = NULL; int h = 0; list_t *me; if (mouseY < 0 || mouseY >= mglst->nTotalItemH) return -1; mglist_for_each (me, mglst) { pci = (PSVITEMDATA)mglist_entry (me); h += pci->nItemHeight; if (h > mouseY) break; ret++; } if (pRet) *pRet = (MgItem *)pci; if (item_y) *item_y = h - pci->nItemHeight; return ret; } int scrollview_is_in_item (PSVDATA psvdata, int mousey, HSVITEM *phsvi, int *itemy) { return isInItem ((MgList *)&psvdata->svlist, 0, mousey, (MgItem **)phsvi, itemy); } /* ---------------------------------------------------------------------------- */ HSVITEM scrollview_add_item (HWND hWnd, PSVDATA psvdata, HSVITEM prehsvi, PSVITEMINFO pii, int *idx) { PSVLIST psvlist = &psvdata->svlist; PSVITEMDATA pci; int index; if ( (pci =svlistItemAdd (psvlist, (PSVITEMDATA)prehsvi, NULL, pii, &index)) ) { mglist_adjust_items_height (hWnd, (MgList *)psvlist, psvscr, pci->nItemHeight); } if (idx) *idx = index; return (HSVITEM)pci; } //FIXME HSVITEM scrollview_add_item_ex (HWND hWnd, PSVDATA psvdata, HSVITEM prehsvi, HSVITEM nexthsvi, PSVITEMINFO pii, int *idx) { PSVLIST psvlist = &psvdata->svlist; PSVITEMDATA pci; int index; if ( (pci =svlistItemAdd (psvlist, (PSVITEMDATA)prehsvi, (PSVITEMDATA)nexthsvi, pii, &index)) ) { mglist_adjust_items_height (hWnd, (MgList *)psvlist, psvscr, pci->nItemHeight); } if (idx) *idx = index; return (HSVITEM)pci; } int scrollview_move_item (PSVDATA psvdata, HSVITEM hsvi, HSVITEM prehsvi) { PSVITEMDATA pci, preitem; if (!hsvi) return -1; pci = (PSVITEMDATA)hsvi; preitem = (PSVITEMDATA)prehsvi; mglist_move_item ((MgList *)&psvdata->svlist, (MgItem *)pci, (MgItem *)preitem); scrollview_refresh_content (psvdata); return 0; } int scrollview_del_item (HWND hWnd, PSVDATA psvdata, int nItem, HSVITEM hsvi) { PSVLIST psvlist = &psvdata->svlist; PSVITEMDATA pci; int del_h; if (hsvi) pci = (PSVITEMDATA)hsvi; else { if ( !(pci=(PSVITEMDATA)mglist_getitem_byindex((MgList *)psvlist, nItem)) ) return -1; } del_h = pci->nItemHeight; if (svlistItemDel (psvlist, pci) >= 0) { mglist_adjust_items_height (hWnd, (MgList *)psvlist, psvscr, -del_h); } return 0; } DWORD scrollview_get_item_adddata (HSVITEM hsvi) { return mglist_get_item_adddata (hsvi); } int scrollview_get_item_index (HWND hWnd, HSVITEM hsvi) { PSVDATA psvdata = (PSVDATA)GetWindowAdditionalData2(hWnd); return mglist_get_item_index ((MgList *)&psvdata->svlist, (MgItem *)hsvi); } int scrollview_is_item_hilight (HWND hWnd, HSVITEM hsvi) { PSVDATA psvdata = (PSVDATA)GetWindowAdditionalData2(hWnd); return (int)mglist_is_item_hilight ((MgList *)&psvdata->svlist, (MgItem *)hsvi); } int scrollview_is_item_selected (HSVITEM hsvi) { return mglist_is_item_selected ((MgItem *)hsvi); } static int svGetItemRect (PSVDATA psvdata, HSVITEM hsvi, RECT *rcItem, BOOL bConv) { PSVITEMDATA pci = (PSVITEMDATA)hsvi; if (!rcItem || !hsvi) return -1; rcItem->top = scrollview_get_item_ypos (psvdata, hsvi); if (bConv) scrolled_content_to_window ((PSCRDATA)psvdata, NULL, &rcItem->top); rcItem->bottom = rcItem->top + pci->nItemHeight; rcItem->left = 0; if (bConv) scrolled_content_to_window ((PSCRDATA)psvdata, &rcItem->left, NULL); //FIXME rcItem->right = rcItem->left + MAX(psvscr->nContWidth, psvscr->visibleWidth); /* only y position is important */ return 1; } int scrollview_get_item_rect (HWND hWnd, HITEM hsvi, RECT *rcItem, BOOL bConv) { PSVDATA psvdata = (PSVDATA)GetWindowAdditionalData2(hWnd); return svGetItemRect (psvdata, hsvi, rcItem, bConv); } int scrollview_get_item_ypos (PSVDATA psvdata, HSVITEM hsvi) { PSVLIST psvlist = &psvdata->svlist; PSVITEMDATA ci = (PSVITEMDATA)hsvi, pci; list_t *me; int h = 0; mglist_for_each (me, psvlist) { pci = (PSVITEMDATA)mglist_entry (me); if (pci == ci) return h; h += pci->nItemHeight; } return -1; } int scrollview_set_item_height (HWND hWnd, HSVITEM hsvi, int height) { PSVDATA psvdata = (PSVDATA)GetWindowAdditionalData2(hWnd); PSVITEMDATA pci = (PSVITEMDATA)hsvi; int diff; if (!psvdata || !pci || height < 0 || height == pci->nItemHeight) return -1; diff = height - pci->nItemHeight; pci->nItemHeight = height; mglist_adjust_items_height (hWnd, (MgList *)&psvdata->svlist, psvscr, diff); return height - diff; } SVITEM_DRAWFUNC scrollview_set_itemdraw (PSVDATA psvdata, SVITEM_DRAWFUNC draw_func) { SVITEM_DRAWFUNC oldfn; oldfn = mglist_set_itemdraw((MgList *)&psvdata->svlist, draw_func); scrollview_refresh_content (psvdata); return oldfn; } void scrollview_reset_content (HWND hWnd, PSVDATA psvdata) { /* delete all svlist content */ //svlist_reset_content (hsvwnd, &psvdata->svlist); if (psvscr->sbPolicy != SB_POLICY_ALWAYS) { ShowScrollBar (hWnd, SB_HORZ, FALSE); ShowScrollBar (hWnd, SB_VERT, FALSE); } /* reset content and viewport size */ scrolled_init_contsize (hWnd, psvscr); /* reset svlist window */ //scrollview_set_svlist (hWnd, psvscr); /* reset viewport window */ scrolled_set_visible (hWnd, psvscr); scrolled_set_hscrollinfo (hWnd, psvscr); scrolled_set_vscrollinfo (hWnd, psvscr); /* delete all svlist content */ svlist_reset_content (hsvwnd, &psvdata->svlist); //FIXME //scrollview_refresh_content (psvdata); InvalidateRect (hWnd, NULL, TRUE); } /* -------------------------------------------------------------------------- */ void scrollview_draw (HWND hWnd, HDC hdc, PSVDATA psvdata) { list_t *me; PSVITEMDATA pci; RECT rcDraw; int h = 0; RECT rcVis; PSVLIST psvlist = &psvdata->svlist; rcDraw.left = 0; rcDraw.top = 0; rcDraw.right = MAX(psvscr->nContWidth, psvscr->visibleWidth); rcDraw.bottom = MAX(psvscr->nContHeight, psvscr->visibleHeight); scrolled_content_to_window (psvscr, &rcDraw.left, &rcDraw.top); scrolled_content_to_window (psvscr, &rcDraw.right, &rcDraw.bottom); scrolled_get_visible_rect (psvscr, &rcVis); ClipRectIntersect (hdc, &rcVis); mglist_for_each (me, psvlist) { pci = (PSVITEMDATA)mglist_entry (me); rcDraw.top += h; rcDraw.bottom = rcDraw.top + pci->nItemHeight; if (rcDraw.bottom < rcVis.top) { h = pci->nItemHeight; continue; } if (rcDraw.top > rcVis.bottom) break; if (((MgList *)psvlist)->iop.drawItem && pci->nItemHeight > 0) { ((MgList *)psvlist)->iop.drawItem (hWnd, (HSVITEM)pci, hdc, &rcDraw); } h = pci->nItemHeight; } } /* adjust the position and size of the svlist window */ void scrollview_set_svlist (HWND hWnd, PSCRDATA pscrdata, BOOL visChanged) { PSVDATA psvdata = (PSVDATA) GetWindowAdditionalData2 (hWnd); if (visChanged) InvalidateRect (hWnd, NULL, TRUE); else { //should be ScrollWindow ? //scrollview_refresh_content (psvdata); scrolled_refresh_view (&psvdata->scrdata); } } static int svlist_init (HWND hWnd, PSVLIST psvlist) { mglist_init((MgList *)psvlist, hWnd); psvlist->nDefItemHeight = SV_DEF_ITEMHEIGHT; ((MgList *)psvlist)->iop.getRect = scrollview_get_item_rect; ((MgList *)psvlist)->iop.isInItem = isInItem; return 0; } /* * initialize scrollview internal structure */ static int svInitData (HWND hWnd, PSVDATA psvdata) { RECT rcWnd; GetClientRect (hWnd, &rcWnd); scrolled_init (hWnd, psvscr, RECTW(rcWnd) - SV_LEFTMARGIN - SV_RIGHTMARGIN, RECTH(rcWnd) - SV_TOPMARGIN - SV_BOTTOMMARGIN); scrolled_init_margins (psvscr, SV_LEFTMARGIN, SV_TOPMARGIN, SV_RIGHTMARGIN, SV_BOTTOMMARGIN); svlist_init (hWnd, &psvdata->svlist); psvscr->move_content = scrollview_set_svlist; //psvdata->flags = 0; return 0; } /* * shoulded be called before scrollview is used * hWnd: the scrolled window */ int scrollview_init (HWND hWnd, PSVDATA psvdata) { if (!psvdata) return -1; SetWindowAdditionalData2 (hWnd, 0); //ShowScrollBar (hWnd, SB_HORZ, FALSE); //ShowScrollBar (hWnd, SB_VERT, FALSE); svInitData (hWnd, psvdata); SetWindowAdditionalData2 (hWnd, (DWORD) psvdata); /* set scrollbar status */ scrolled_set_hscrollinfo (hWnd, psvscr); scrolled_set_vscrollinfo (hWnd, psvscr); return 0; } /* * destroy a scrollview */ void scrollview_destroy (PSVDATA psvdata) { svlist_reset_content (hsvwnd, &psvdata->svlist); } /* --------------------------------------------------------------------------------- */ LRESULT ScrollViewCtrlProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { PSVDATA psvdata = NULL; if (message != MSG_CREATE) { psvdata = (PSVDATA) GetWindowAdditionalData2 (hWnd); /* not used vars PSVLIST psvlist = NULL; psvlist = &psvdata->svlist; */ } switch (message) { case MSG_CREATE: { psvdata = (PSVDATA) malloc(sizeof (SVDATA)); if (!psvdata) return -1; scrollview_init (hWnd, psvdata); if (GetWindowStyle(hWnd) & SVS_AUTOSORT) { scrollview_set_autosort (psvdata); } break; } case MSG_DESTROY: { /* suppress a warning about calling free() before using the pointer */ PSVDATA svdata = (PSVDATA) GetWindowAdditionalData2 (hWnd); if (svdata) { scrollview_destroy(svdata); free (svdata); } break; } case MSG_GETDLGCODE: return DLGC_WANTARROWS; case MSG_KEYDOWN: { HSVITEM hsvi = 0, curHilighted; curHilighted = (HSVITEM) mglist_get_hilighted_item((MgList *)&psvdata->svlist); if (wParam == SCANCODE_CURSORBLOCKDOWN) { hsvi = scrollview_get_next_item(psvdata, curHilighted); if (GetWindowStyle(hWnd) & SVS_LOOP && !hsvi) { hsvi = scrollview_get_next_item(psvdata, 0); } } else if (wParam == SCANCODE_CURSORBLOCKUP) { hsvi = scrollview_get_prev_item(psvdata, curHilighted); if (GetWindowStyle(hWnd) & SVS_LOOP && !hsvi) { hsvi = scrollview_get_prev_item(psvdata, 0); } } else if (wParam == SCANCODE_HOME) { hsvi = scrollview_get_next_item(psvdata, 0); } else if (wParam == SCANCODE_END) { hsvi = scrollview_get_prev_item(psvdata, 0); } /* skip the invisible items */ while ( hsvi && ((PSVITEMDATA)hsvi)->nItemHeight <= 0 ) { hsvi = (wParam == SCANCODE_CURSORBLOCKDOWN || wParam == SCANCODE_HOME) ? scrollview_get_next_item(psvdata, hsvi) : scrollview_get_prev_item(psvdata, hsvi); } if (hsvi) { if (hsvi != curHilighted) { NotifyParentEx (hWnd, GetDlgCtrlID(hWnd), SVN_SELCHANGING, (DWORD)curHilighted); scrollview_hilight_item (psvdata, hsvi); NotifyParentEx (hWnd, GetDlgCtrlID(hWnd), SVN_SELCHANGED, (DWORD)hsvi); } scrollview_make_item_visible (psvdata, hsvi); } break; } //FIXME, moved to listmode.c case MSG_PAINT: { HDC hdc = BeginPaint (hWnd); scrollview_draw (hWnd, hdc, psvdata); EndPaint (hWnd, hdc); return 0; } case SVM_ADDITEM: { int idx; HSVITEM hsvi; hsvi = scrollview_add_item (hWnd, psvdata, 0, (PSVITEMINFO)lParam, &idx); if (wParam) *(HSVITEM *)wParam = hsvi; return idx; } case SVM_DELITEM: scrollview_del_item (hWnd, psvdata, wParam, (HSVITEM)lParam); return 0; case SVM_RESETCONTENT: scrollview_reset_content (hWnd, psvdata); return 0; case SVM_SETITEMHEIGHT: { int nItem = (int)wParam; int new_h = (int)lParam; HSVITEM hsvi; hsvi = scrollview_get_item_by_index (psvdata, nItem); scrollview_set_item_height (hWnd, hsvi, new_h); return 0; } }/* end switch */ //return DefaultScrolledProc (hWnd, message, wParam, lParam); return DefaultItemViewProc (hWnd, message, wParam, lParam, psvscr, (MgList *)&psvdata->svlist); } BOOL RegisterScrollViewControl (void) { WNDCLASS WndClass; WndClass.spClassName = CTRL_SCROLLVIEW; WndClass.dwStyle = WS_NONE; WndClass.dwExStyle = WS_EX_NONE; WndClass.hCursor = GetSystemCursor (IDC_ARROW); #ifdef _MGSCHEMA_COMPOSITING WndClass.dwBkColor = GetWindowElementAttr (HWND_NULL, WE_BGC_WINDOW); #else WndClass.iBkColor = GetWindowElementPixelEx (HWND_NULL, HDC_SCREEN, WE_BGC_WINDOW); #endif WndClass.WinProc = ScrollViewCtrlProc; return gui_AddNewControlClass (&WndClass) == ERR_OK; } #endif /* _MGCTRL_SCROLLVIEW */