Numerous bug fixes to all platforms
Works both installed and not installed
This commit is contained in:
parent
c913f9f99a
commit
a81ea73566
68 changed files with 384 additions and 35286 deletions
|
@ -1,319 +0,0 @@
|
|||
/* MinWin Scroll classes
|
||||
*
|
||||
* ScrollBar and ScrollPane
|
||||
*
|
||||
* Written by Ben Hinkle and released to the public domain, as
|
||||
* explained at http://creativecommons.org/licenses/publicdomain
|
||||
* Report comments and bugs at dsource: http://www.dsource.org/projects/minwin
|
||||
*/
|
||||
|
||||
module minwin.scroll;
|
||||
|
||||
public import minwin.component;
|
||||
|
||||
private {
|
||||
import minwin.app;
|
||||
import minwin.window;
|
||||
import minwin.peerimpl;
|
||||
import std.string;
|
||||
import minwin.logging;
|
||||
}
|
||||
|
||||
version (GTK) version = SharedScrollData;
|
||||
version (SharedScrollData) {
|
||||
struct ScrollData {
|
||||
int min;
|
||||
int max;
|
||||
int increment;
|
||||
int value;
|
||||
}
|
||||
}
|
||||
enum ScrollMask {
|
||||
Range = 1, Increment = 2, Value = 4
|
||||
}
|
||||
const int Horizontal = 1;
|
||||
const int Vertical = 2;
|
||||
|
||||
version (MinWin32) {
|
||||
|
||||
private import minwin.mswindows;
|
||||
|
||||
alias SCROLLINFO ScrollData;
|
||||
|
||||
class ScrollBar : WindowChild {
|
||||
int orientation;
|
||||
this(Component parent, int orientation, char[] name = "") {
|
||||
PeerForAdd parentp = parent.getPeerForAdd();
|
||||
uint style = orientation==Horizontal?SBS_HORZ:SBS_VERT;
|
||||
peer = CreateWindowA("SCROLLBAR","",
|
||||
style | WS_CHILD | WS_VISIBLE,
|
||||
0,0,10,10,parentp,
|
||||
cast(HMENU)0,gApp.hInstance,null);
|
||||
sysAssert(peer !is null, "Failed to create peer scrollbar");
|
||||
this.name = name;
|
||||
setWindowChildPeer(this,peer,OWNS_PEER);
|
||||
parent.addChild(this);
|
||||
}
|
||||
Point preferredSize() {
|
||||
int width,height;
|
||||
if (orientation == Vertical) {
|
||||
height = 50;
|
||||
width = 16;
|
||||
} else {
|
||||
height = 16;
|
||||
width = 50;
|
||||
}
|
||||
if (userPreferredWidth > 0)
|
||||
width = userPreferredWidth;
|
||||
if (userPreferredHeight > 0)
|
||||
height = userPreferredHeight;
|
||||
return XY(width,height);
|
||||
}
|
||||
mixin WindowChildImpl!();
|
||||
|
||||
private uint windowsMask(uint mask) {
|
||||
uint res = 0;
|
||||
if (mask & ScrollMask.Range)
|
||||
res |= SIF_RANGE;
|
||||
if (mask & ScrollMask.Value)
|
||||
res |= SIF_POS;
|
||||
if (mask & ScrollMask.Increment)
|
||||
res |= SIF_PAGE;
|
||||
return res;
|
||||
}
|
||||
|
||||
void setData(inout ScrollData state, uint mask) {
|
||||
state.cbSize = SCROLLINFO.sizeof;
|
||||
state.fMask = windowsMask(mask);
|
||||
SetScrollInfo(peer,SB_CTL,&state, false);
|
||||
}
|
||||
void getData(inout ScrollData state, uint mask) {
|
||||
state.cbSize = SCROLLINFO.sizeof;
|
||||
state.fMask = windowsMask(mask);
|
||||
GetScrollInfo(peer,SB_CTL,&state);
|
||||
}
|
||||
int value() {
|
||||
ScrollData state;
|
||||
getData(state,ScrollMask.Value);
|
||||
return state.nPos;
|
||||
}
|
||||
}
|
||||
|
||||
class ScrollPane : WindowChild {
|
||||
Point origin;
|
||||
|
||||
// how to customize page size and steps and limits? need API to each scrollbar
|
||||
|
||||
int hstep = 1; // given bounds of child this is how quickly to move through it
|
||||
int vstep = 1;
|
||||
|
||||
this(Component parent, int orientations = Horizontal | Vertical, char[] name = "") {
|
||||
PeerForAdd parentp = parent.getPeerForAdd();
|
||||
int style;
|
||||
if (orientations & Horizontal) style |= WS_HSCROLL;
|
||||
if (orientations & Vertical) style |= WS_VSCROLL;
|
||||
peer = CreateWindowA("MinWinScrollWindow","",
|
||||
style | WS_CHILD | WS_VISIBLE,
|
||||
0,0,50,50,parentp,
|
||||
cast(HMENU)0,gApp.hInstance,null);
|
||||
this.name = name;
|
||||
clearBackgroundOnPaint = false;
|
||||
setWindowChildPeer(this,peer,OWNS_PEER);
|
||||
parent.addChild(this);
|
||||
}
|
||||
mixin WindowChildImpl!();
|
||||
|
||||
void layout(bool validateParent) {
|
||||
if (parent && validateParent)
|
||||
parent.layout(true);
|
||||
if (childLayoutDirty && child) {
|
||||
Point s = child.preferredSize;
|
||||
Rect r = LTWH(origin.x,origin.y,s.x,s.y);
|
||||
child.setBounds(r);
|
||||
childLayoutDirty = false;
|
||||
}
|
||||
foreach( Component ch; this) {
|
||||
ch.layout(false);
|
||||
}
|
||||
}
|
||||
|
||||
int WindowProc(HWND hWnd, uint uMsg, WPARAM wParam, LPARAM lParam) {
|
||||
version (LOG) log.printf(" in ScrollPane windowproc msg %d\n",uMsg);
|
||||
bool doDefault = true;
|
||||
if (uMsg == WM_HSCROLL) {
|
||||
SCROLLINFO data;
|
||||
data.cbSize = SCROLLINFO.sizeof;
|
||||
data.fMask = SIF_ALL;
|
||||
GetScrollInfo(hWnd, SB_HORZ, &data);
|
||||
int cmd = LOWORD(wParam);
|
||||
int oldPos = data.nPos;
|
||||
if (cmd == SB_LINELEFT) data.nPos--;
|
||||
if (cmd == SB_LINERIGHT) data.nPos++;
|
||||
if (cmd == SB_PAGELEFT) data.nPos -= data.nPage;
|
||||
if (cmd == SB_PAGERIGHT) data.nPos += data.nPage;
|
||||
data.fMask = SIF_POS;
|
||||
SetScrollInfo(hWnd, SB_HORZ, &data, true);
|
||||
GetScrollInfo(hWnd, SB_HORZ, &data);
|
||||
if (data.nPos != oldPos) {
|
||||
int step = hstep*(oldPos-data.nPos);
|
||||
ScrollWindowEx(hWnd,step,0,null,null,null,null,SW_INVALIDATE | SW_ERASE);
|
||||
// ScrollWindow(hWnd,step,0,null,null);
|
||||
if (child) {
|
||||
WindowChild wc = cast(WindowChild)child;
|
||||
MoveWindow(wc.getPeer,step,0,0,0,false);
|
||||
UpdateWindow(wc.getPeer);
|
||||
}
|
||||
origin.XY(origin.x + step, origin.y);
|
||||
}
|
||||
doDefault = false;
|
||||
} else if (uMsg == WM_VSCROLL) {
|
||||
SCROLLINFO data;
|
||||
data.cbSize = SCROLLINFO.sizeof;
|
||||
data.fMask = SIF_ALL;
|
||||
GetScrollInfo(hWnd, SB_VERT, &data);
|
||||
int cmd = LOWORD(wParam);
|
||||
int oldPos = data.nPos;
|
||||
if (cmd == SB_LINEUP) data.nPos--;
|
||||
if (cmd == SB_LINEDOWN) data.nPos++;
|
||||
if (cmd == SB_PAGEUP) data.nPos -= data.nPage;
|
||||
if (cmd == SB_PAGEDOWN) data.nPos += data.nPage;
|
||||
data.fMask = SIF_POS;
|
||||
SetScrollInfo(hWnd, SB_VERT, &data, true);
|
||||
GetScrollInfo(hWnd, SB_VERT, &data);
|
||||
if (data.nPos != oldPos) {
|
||||
int step = vstep*(oldPos-data.nPos);
|
||||
ScrollWindowEx(hWnd,0,step,null,null,null,null,SW_INVALIDATE | SW_ERASE);
|
||||
// ScrollWindow(hWnd,0,step,null,null);
|
||||
if (child) {
|
||||
WindowChild wc = cast(WindowChild)child;
|
||||
MoveWindow(wc.getPeer,0,step,0,0,false);
|
||||
UpdateWindow(wc.getPeer);
|
||||
}
|
||||
origin.XY(origin.x, origin.y + step);
|
||||
}
|
||||
doDefault = false;
|
||||
}
|
||||
return doDefault;
|
||||
}
|
||||
}
|
||||
|
||||
extern(Windows) int MinWinScrollWindowProc(HWND hWnd, uint uMsg, WPARAM wParam, LPARAM lParam) {
|
||||
version(LOG) log.printf("in minwin scroll window proc hwnd %p %d %d %d\n",hWnd,uMsg,wParam,lParam);
|
||||
bool doDefault = true;
|
||||
ScrollPane pane = cast(ScrollPane)peerToWindowChild(hWnd);
|
||||
version(LOG) log.printf("in minwin scroll window proc win %p\n",pane);
|
||||
if (pane !is null)
|
||||
doDefault = pane.WindowProc(hWnd,uMsg,wParam,lParam) != 0;
|
||||
if (doDefault)
|
||||
return DefWindowProcA(hWnd, uMsg, wParam, lParam);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
static this() {
|
||||
HINSTANCE hInst = GetModuleHandleA(null);
|
||||
WNDCLASSA wc;
|
||||
wc.lpszClassName = "MinWinScrollWindow";
|
||||
wc.style = CS_CLASSDC | CS_HREDRAW | CS_VREDRAW;
|
||||
wc.lpfnWndProc = &MinWinScrollWindowProc;
|
||||
wc.hInstance = hInst;
|
||||
wc.hIcon = LoadIconA(cast(HINSTANCE) null, IDI_APPLICATION);
|
||||
// wc.hIconSm = DefaultWindowSmallIcon.peer;
|
||||
wc.hCursor = LoadCursorA(cast(HINSTANCE) null, IDC_ARROW);
|
||||
wc.hbrBackground = cast(HBRUSH) (COLOR_WINDOW + 1); // not +1 for default
|
||||
wc.lpszMenuName = null;
|
||||
wc.cbClsExtra = 0;
|
||||
wc.cbWndExtra = 0;
|
||||
RegisterClassA(&wc);
|
||||
}
|
||||
|
||||
} else version (GTK) {
|
||||
|
||||
private import minwin.gtk;
|
||||
private import minwin.gtk_peers;
|
||||
|
||||
class ScrollBar : WindowChild {
|
||||
this(Component parent, int orientation, char[] name = "") {
|
||||
PeerForAdd parentp = parent.getPeerForAdd();
|
||||
this.name = name;
|
||||
if (orientation == Horizontal)
|
||||
peer = gtk_hscrollbar_new(null);
|
||||
else
|
||||
peer = gtk_vscrollbar_new(null);
|
||||
gtk_container_add(cast(GtkContainer*)parentp,peer);
|
||||
setWindowChildPeer(this,peer,OWNS_PEER);
|
||||
parent.addChild(this);
|
||||
gtk_widget_realize(peer);
|
||||
visible = true;
|
||||
}
|
||||
|
||||
mixin WindowChildImpl!();
|
||||
|
||||
}
|
||||
|
||||
class ScrollPane : WindowChild {
|
||||
MinWinGtkPeer* content;
|
||||
this(Component parent, int orientations = Horizontal | Vertical, char[] name = "") {
|
||||
PeerForAdd parentp = parent.getPeerForAdd();
|
||||
this.name = name;
|
||||
peer = gtk_scrolled_window_new(null,null);
|
||||
gtk_container_add(cast(GtkContainer*)parentp,peer);
|
||||
GtkWidget* view = gtk_viewport_new(null,null);
|
||||
gtk_container_add(cast(GtkContainer*)peer,view);
|
||||
|
||||
// add our peer to hook into GTK size allocation algorithm
|
||||
GtkWidget* wcontent = MinWinGtkPeer_new();
|
||||
content = cast(MinWinGtkPeer*)wcontent;
|
||||
gtk_widget_set_sensitive(wcontent,true);
|
||||
content.sizeRequest = >kRequest;
|
||||
content.sizeAllocate = >kAllocate;
|
||||
gtk_container_add(cast(GtkContainer*)view,wcontent);
|
||||
|
||||
setWindowChildPeer(this,peer,OWNS_PEER);
|
||||
parent.addChild(this);
|
||||
|
||||
// are all of these really needed?
|
||||
gtk_widget_realize(wcontent);
|
||||
gtk_widget_show(wcontent);
|
||||
gtk_widget_realize(view);
|
||||
gtk_widget_show(view);
|
||||
gtk_widget_realize(peer);
|
||||
visible = true;
|
||||
}
|
||||
|
||||
mixin WindowChildImpl!();
|
||||
|
||||
void layout(bool validateParent) {
|
||||
if (parent && validateParent)
|
||||
parent.layout(true);
|
||||
childLayoutDirty = false;
|
||||
}
|
||||
|
||||
PeerForAdd getPeerForAdd() {
|
||||
return cast(GtkWidget*)content;
|
||||
}
|
||||
|
||||
// callback from the GTK peer asking for preferred size
|
||||
private void gtkRequest(GtkWidget *w, GtkRequisition* req) {
|
||||
version(LOG)log.writefln("gtkRequest for scrollpane");
|
||||
Component ch = child;
|
||||
if (ch is null) return;
|
||||
Point s = ch.preferredSize;
|
||||
req.width = s.x;
|
||||
req.height = s.y;
|
||||
version(LOG)log.writefln("done gtkRequest for scrollpane");
|
||||
}
|
||||
|
||||
// callback from GTK peer telling us our position
|
||||
private void gtkAllocate(GtkWidget *w, GtkAllocation* req) {
|
||||
version(LOG)log.writefln("gtkAllocate for scrollpane");
|
||||
Component ch = child;
|
||||
if (ch is null) return;
|
||||
Rect r = toRect(*req);
|
||||
ch.size = XY(r.width,r.height);
|
||||
ch.layout(false);
|
||||
childLayoutDirty = false;
|
||||
version(LOG)log.writefln("done gtkAllocate for scrollpane");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue