1 /*$
2  Copyright (C) 2013-2020 Azel.
3 
4  This file is part of AzPainter.
5 
6  AzPainter is free software: you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  AzPainter is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 $*/
19 
20 /*****************************************
21  * mContainerView
22  *****************************************/
23 
24 #include "mDef.h"
25 #include "mWidget.h"
26 #include "mEvent.h"
27 #include "mScrollBar.h"
28 #include "mWidget_pv.h"
29 
30 #include "mContainerView.h"
31 
32 
33 /*********************//**
34 
35 @defgroup containerview mContainerView
36 @brief コンテナを垂直スクロールできるビュー
37 
38 - 内容ウィジェットはこのウィジェットの子として作成し、mContainerViewData::area にウィジェットポインタをセットする。
39 
40 <h2>継承</h2>
41 mWidget \> mContainerView
42 
43 @ingroup group_widget
44 @{
45 
46 @file mContainerView.h
47 
48 @struct mContainerView
49 @struct mContainerViewData
50 @enum MCONTAINERVIEW_STYLE
51 
52 *************************/
53 
54 
55 
56 /** スクロールバー、イベントハンドラ */
57 
_scrollbar_evhandle(mWidget * wg,mEvent * ev)58 static int _scrollbar_evhandle(mWidget *wg,mEvent *ev)
59 {
60 	//ホイールでスクロール
61 
62 	if(ev->type == MEVENT_SCROLL
63 		&& (ev->scr.dir == MEVENT_SCROLL_DIR_DOWN || ev->scr.dir == MEVENT_SCROLL_DIR_UP))
64 	{
65 		mScrollBar *scr = M_SCROLLBAR(wg);
66 		mContainerView *p = M_CONTAINERVIEW(scr->wg.param);
67 
68 		if(mScrollBarMovePos(scr, (ev->scr.dir == MEVENT_SCROLL_DIR_UP)? -30: 30))
69 			mWidgetMove(M_WIDGET(p->cv.area), 0, -(scr->sb.pos));
70 
71 		return 1;
72 	}
73 
74 	return mScrollBarEventHandle(wg, ev);
75 }
76 
77 /** スクロールバー操作時 */
78 
_scrollbar_handle(mScrollBar * scrb,int pos,int flags)79 static void _scrollbar_handle(mScrollBar *scrb,int pos,int flags)
80 {
81 	mContainerView *p = M_CONTAINERVIEW(scrb->wg.param);
82 
83 	if(flags & MSCROLLBAR_N_HANDLE_F_CHANGE)
84 		mWidgetMove(M_WIDGET(p->cv.area), 0, -pos);
85 }
86 
87 /** スクロール情報セット */
88 
_set_scrollinfo(mContainerView * p)89 static void _set_scrollinfo(mContainerView *p)
90 {
91 	mScrollBarSetStatus(p->cv.scrv, 0, (p->cv.area)? p->cv.area->hintH: 0, p->wg.h);
92 }
93 
94 /** スクロールバーの表示/非表示
95  *
96  * @return 表示の有無が変化したか */
97 
_showScrollBar(mContainerView * p)98 static mBool _showScrollBar(mContainerView *p)
99 {
100 	int fscr;
101 	mBool ret = FALSE;
102 
103 	if(p->cv.style & MCONTAINERVIEW_S_FIX_SCROLL)
104 		fscr = 1;
105 	else
106 		fscr = (p->cv.area && p->cv.area->hintH > p->wg.h);
107 
108 	if(mWidgetIsVisible(M_WIDGET(p->cv.scrv)) != fscr)
109 	{
110 		mWidgetShow(M_WIDGET(p->cv.scrv), fscr);
111 		ret = TRUE;
112 	}
113 
114 	return ret;
115 }
116 
117 /** レイアウト */
118 
_layout_handle(mWidget * wg)119 static void _layout_handle(mWidget *wg)
120 {
121 	mContainerView *p = M_CONTAINERVIEW(wg);
122 	int fscr,h;
123 
124 	fscr = mWidgetIsVisible(M_WIDGET(p->cv.scrv));
125 
126 	//内容
127 
128 	if(p->cv.area)
129 	{
130 		/* 内容の高さの方が長ければ、内容の最大高さのサイズにする。
131 		 * ウィジェットの高さの方が大きければ、そのまま */
132 
133 		h = (p->cv.area)->hintH;
134 
135 		mWidgetMoveResize(p->cv.area,
136 			0, -(p->cv.scrv)->sb.pos,
137 			wg->w - (fscr? MSCROLLBAR_WIDTH: 0),
138 			(h > wg->h)? h: wg->h);
139 	}
140 
141 	//スクロールバー
142 
143 	if(fscr)
144 	{
145 		mWidgetMoveResize(M_WIDGET(p->cv.scrv),
146 			wg->w - MSCROLLBAR_WIDTH, 0, MSCROLLBAR_WIDTH, wg->h);
147 	}
148 }
149 
150 /** サイズ変更時 */
151 
_onsize_handle(mWidget * wg)152 static void _onsize_handle(mWidget *wg)
153 {
154 	mContainerView *p = M_CONTAINERVIEW(wg);
155 
156 	_set_scrollinfo(p);
157 
158 	_showScrollBar(p);
159 }
160 
161 /** 推奨サイズ計算 */
162 
_calchint_handle(mWidget * wg)163 static void _calchint_handle(mWidget *wg)
164 {
165 	mWidget *area = M_CONTAINERVIEW(wg)->cv.area;
166 
167 	//[!] 高さはセットしない
168 
169 	if(area)
170 	{
171 		__mWidgetCalcHint(area);
172 
173 		wg->hintW = area->hintW + MSCROLLBAR_WIDTH;
174 	}
175 }
176 
177 
178 //========================
179 // main
180 //========================
181 
182 
183 /** 作成 */
184 
mContainerViewNew(int size,mWidget * parent,uint32_t style)185 mContainerView *mContainerViewNew(int size,mWidget *parent,uint32_t style)
186 {
187 	mContainerView *p;
188 	mScrollBar *scr;
189 
190 	if(size < sizeof(mContainerView)) size = sizeof(mContainerView);
191 
192 	p = (mContainerView *)mWidgetNew(size, parent);
193 	if(!p) return NULL;
194 
195 	p->wg.layout = _layout_handle;
196 	p->wg.onSize = _onsize_handle;
197 	p->wg.calcHint = _calchint_handle;
198 	p->wg.draw = mWidgetHandleFunc_draw_drawBkgnd;
199 
200 	p->cv.style = style;
201 
202 	//スクロールバー
203 
204 	p->cv.scrv = scr = mScrollBarNew(0, M_WIDGET(p), MSCROLLBAR_S_VERT);
205 
206 	scr->wg.notifyTarget = MWIDGET_NOTIFYTARGET_PARENT;
207 	scr->wg.param = (intptr_t)p;
208 	scr->wg.fEventFilter |= MWIDGET_EVENTFILTER_SCROLL;
209 	scr->wg.event = _scrollbar_evhandle;
210 	scr->sb.handle = _scrollbar_handle;
211 
212 	return p;
213 }
214 
215 /** 構成を行う
216  *
217  * 中身の状態が変わった時に手動で更新したい場合。\n
218  * mWidgetReLayout() を使う場合は実行しなくて良い。\n
219  * スクロールバーの有無の再判定と再レイアウトを行う。 */
220 
mContainerViewConstruct(mContainerView * p)221 void mContainerViewConstruct(mContainerView *p)
222 {
223 	/* 中身の高さが変わった場合があるので、常に再レイアウトを行う */
224 
225 	_showScrollBar(p);
226 	_set_scrollinfo(p);
227 
228 	_layout_handle(M_WIDGET(p));
229 }
230 
231 /* @} */
232