Drawing a splitter with GDI?

BlitzMax Forums/BlitzMax GUI Programming/Drawing a splitter with GDI?

I finished my splitter control which separates viewports, but I'm not happy with the way its displayed when I am dragging the splitter. In Hammer, the program draws semi-transparent lines as you drag the mouse. I'm assuming this is done with GDI drawing, because the appearance is similar to how mouse icons look.



Here you can see that the lines are somewhat blended with what lies underneath them:


How can I draw lines like these on a window?

You need to create a geometric pen (otherwise linesize is always fixed to 1). Using ExtCreatePen()

Set the line width.

Pen style will be dashed/hatched or whatever

Set the foreground mix mode (using SetROP2() in GDI) to do an XOR of the pen with the foreground

Draw the lines

Draw overthem with an XOR mode again to delete them non-destructively

Code?

Quickly hacked together but you get the idea :-

SuperStrict


Extern "win32"
	Function ExtCreatePen:Int(style:Int, width:Int, logbrush:Byte Ptr, stylecount:Int, stylePtr:Byte Ptr)="ExtCreatePen@20"
	Function ReleaseDC( hwnd:Int, hdc:Int )
	Function GetCurrentObject( hdc:Int, objectType:Int )
	Function MoveToEx( hdc:Int, x:Int, y:Int, point:Int )
	Function LineTo( hdc:Int, x:Int, y:Int )
	Function GetCursorPos( pPoint:Byte Ptr )
	Function SetROP2( hdc:Int, mode:Int )
EndExtern

Global win:TGadget = CreateWindow("LineTest", 0,0, 400,400 )
Global panel:TGadget = CreatePanel( 0,0,400,400, win, PANEL_ACTIVE )
SetPanelColor panel,100,0,200
SetGadgetLayout panel,1,1,1,1



Type TLogBrush
	Field style:Int
	Field colour:Int
	Field hatch:Int
EndType
Global logBrush:TLogBrush = New TLogBrush
logBrush.style = 2 'BS_HATCHED
logBrush.colour = $ffffffff


Type TPoint
	Field x:Int
	Field y:Int
EndType
Global cursorpos:TPoint = New TPoint



While WaitEvent()
	Select EventID()
		Case EVENT_WINDOWCLOSE
			End
		
		Case EVENT_MOUSEDOWN
			
		Case EVENT_MOUSEMOVE
			DrawCursor()
		
	EndSelect
Wend



Function DrawCursor()
	Global oldX:Int = -1, oldY:Int = -1
	Local pen:Int = ExtCreatePen( $00010000,6,Byte Ptr(logBrush),0,Byte Ptr(0))
	Local hwnd:Int = QueryGadget( panel, QUERY_HWND )
	Local hdc:Int = GetDC( hwnd )

	SelectObject( hdc, pen )
	
	SetROP2( hdc, 7 ) ' R2_XORPEN

	' Draw over old line (clears it because it was drawn with XOR)
	If( oldX <> -1 )
		MoveToEx( hdc, 0, oldY, 0)
		LineTo( hdc, ClientWidth(panel),oldY )
		MoveToEx( hdc, oldX, 0, 0)
		LineTo( hdc, oldX, ClientHeight(panel) )
	EndIf
	
	' Draw new line	
	GetCursorPos( Byte Ptr(cursorpos) )
	oldX = cursorpos.x 
	oldY = cursorpos.y - 50
	MoveToEx( hdc, 0, oldY, 0)
	LineTo( hdc, ClientWidth(panel),oldY )
	MoveToEx( hdc, oldX, 0, 0)
	LineTo( hdc, oldX, ClientHeight(panel) )
	
	ReleaseDC( hwnd, hdc )

	DeleteObject( pen )
EndFunction


Sweet, thank you. A working code examples saves me hours of looking up functions. :)

Hmmm...your example only draws within the panel client area. Even if I draw separately for each affected panel, I still need to be able to draw over the panel borders.

I need to draw on top of everything, not just within a panel client area.

I did figure out how to use a bitmap to get that grey/checker pattern, but I still need to be able to draw on top of everything.

Presuming you're only drawing this while dragging a marker you would make a panel - attached to the window client area - all your other gadgets are on the window as usual (not the panel).

Then you would handle the drawing of the marker until the mouse was released - thus preventing redrawing of the other gadgets... let me modify the code to show you what I mean....


there... hold the left mouse to drag the marker....

[edit] actually this example doesn't quite work because it doesn't get the input onto the other controls - but you get the idea - in your case it wouldn't be a problem because you are only handling the input to your splitter[/edit]

SuperStrict


Extern "win32"
	Function ExtCreatePen:Int(style:Int, width:Int, logbrush:Byte Ptr, stylecount:Int, stylePtr:Byte Ptr)="ExtCreatePen@20"
	Function ReleaseDC( hwnd:Int, hdc:Int )
	Function GetCurrentObject( hdc:Int, objectType:Int )
	Function MoveToEx( hdc:Int, x:Int, y:Int, point:Int )
	Function LineTo( hdc:Int, x:Int, y:Int )
	Function GetCursorPos( pPoint:Byte Ptr )
	Function SetROP2( hdc:Int, mode:Int )
	Function GetAsyncKeyState:Short( key:Int )
	
EndExtern

Global win:TGadget = CreateWindow("LineTest", 0,0, 400,400 )
Global panel:TGadget = CreatePanel( 0,0,400,400, win, PANEL_ACTIVE )
Global button1:TGadget = CreateButton( "Button1", 10,10, 60, 24, win )
Global button2:TGadget = CreateButton( "Button2", 90,10, 60, 24, win )
SetPanelColor panel,100,0,200
SetGadgetLayout panel,1,1,1,1



Type TLogBrush
	Field style:Int
	Field colour:Int
	Field hatch:Int
EndType
Global logBrush:TLogBrush = New TLogBrush
logBrush.style = 2 'BS_HATCHED
logBrush.colour = $ffffffff


Type TPoint
	Field x:Int
	Field y:Int
EndType
Global cursorpos:TPoint = New TPoint

Const VK_LBUTTON:Int = 1


While WaitEvent()
	Select EventID()
		Case EVENT_WINDOWCLOSE
			End
		
		Case EVENT_MOUSEDOWN
			DrawCursor()
			
		Case EVENT_MOUSEMOVE
		
	EndSelect
Wend


Function DrawCursor()
	Local oldX:Int = -1, oldY:Int = -1
	Local erase:Int = False
	
	Local pen:Int = ExtCreatePen( $00010000,6,Byte Ptr(logBrush),0,Byte Ptr(0))
	Local hwnd:Int = QueryGadget( panel, QUERY_HWND )
	Local hdc:Int = GetDC( hwnd )

	SelectObject( hdc, pen )
	
	SetROP2( hdc, 7 ) ' R2_XORPEN

	Repeat
		GetCursorPos( Byte Ptr(cursorpos) )

		' Draw over old line (clears it because it was drawn with XOR)
		If( oldX<>cursorPos.x And oldY<>cursorPos.y )
			If( erase )
				MoveToEx( hdc, 0, oldY, 0)
				LineTo( hdc, ClientWidth(panel),oldY )
				MoveToEx( hdc, oldX, 0, 0)
				LineTo( hdc, oldX, ClientHeight(panel) )
			EndIf
			
			' Draw new line	
			oldX = cursorpos.x 
			oldY = cursorpos.y - 50
			MoveToEx( hdc, 0, oldY, 0)
			LineTo( hdc, ClientWidth(panel),oldY )
			MoveToEx( hdc, oldX, 0, 0)
			LineTo( hdc, oldX, ClientHeight(panel) )
			erase = True
		EndIf
	Until Not (GetAsyncKeyState(VK_LBUTTON) & $8000)

	
	If erase
		' erase marker
		MoveToEx( hdc, 0, oldY, 0)
		LineTo( hdc, ClientWidth(panel),oldY )
		MoveToEx( hdc, oldX, 0, 0)
		LineTo( hdc, oldX, ClientHeight(panel) )
		erase = False
	EndIf
		
	ReleaseDC( hwnd, hdc )

	DeleteObject( pen )
EndFunction




Well, I can draw directly to the desktop. Maybe that is the way to do it.

Yes, that's a better solution, good luck!