From efaeb275f78e18d594d9ee8ff04eccd2dc59512c Mon Sep 17 00:00:00 2001 From: truelight Date: Mon, 9 Aug 2004 17:04:08 +0000 Subject: (svn r1) Import of revision 975 of old (crashed) SVN --- window.c | 1209 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1209 insertions(+) create mode 100644 window.c (limited to 'window.c') diff --git a/window.c b/window.c new file mode 100644 index 000000000..e01066bf4 --- /dev/null +++ b/window.c @@ -0,0 +1,1209 @@ +#include "stdafx.h" +#include "ttd.h" +#include "window.h" +#include "gfx.h" +#include "viewport.h" + +void HandleButtonClick(Window *w, byte widget) +{ + w->click_state |= (1 << widget); + w->flags4 |= 5 << WF_TIMEOUT_SHL; + InvalidateWidget(w, widget); +} + +void DispatchLeftClickEvent(Window *w, int x, int y) { + WindowEvent e; + const Widget *wi; + + e.click.pt.x = x; + e.click.pt.y = y; + e.event = WE_CLICK; + + if (w->desc_flags & WDF_DEF_WIDGET) { + e.click.widget = GetWidgetFromPos(w, x, y); + if (e.click.widget < 0) return; /* exit if clicked outside of widgets */ + + wi = &w->widget[e.click.widget]; + + if (wi->type & 0xE0) { + /* special widget handling */ + switch(wi->type) { + case WWT_IMGBTN | WWB_PUSHBUTTON: + case WWT_TEXTBTN | WWB_PUSHBUTTON: + if (HASBIT(w->disabled_state, e.click.widget)) + return; /* don't allow click if disabled */ + HandleButtonClick(w, e.click.widget); + break; + case WWT_NODISTXTBTN: + if (HASBIT(w->disabled_state, e.click.widget)) + return; /* don't allow click if disabled */ + break; + } + } else if (wi->type == WWT_SCROLLBAR || wi->type == WWT_HSCROLLBAR) { + ScrollbarClickHandler(w, wi, e.click.pt.x, e.click.pt.y); + } + + w->wndproc(w, &e); + + if (w->desc_flags & WDF_STD_BTN) { + if (e.click.widget == 0) DeleteWindow(w); + else { + if (e.click.widget == 1) { + if (_ctrl_pressed) + StartWindowSizing(w); + else + StartWindowDrag(w); + } + } + } + } else { + w->wndproc(w, &e); + } +} + +void DispatchRightClickEvent(Window *w, int x, int y) { + WindowEvent e; + + /* default tooltips handler? */ + if (w->desc_flags & WDF_STD_TOOLTIPS) { + e.click.widget = GetWidgetFromPos(w, x, y); + if (e.click.widget < 0) + return; /* exit if clicked outside of widgets */ + + if (w->widget[e.click.widget].tooltips != 0) { + GuiShowTooltips(w->widget[e.click.widget].tooltips); + return; + } + } + + e.event = WE_RCLICK; + e.click.pt.x = x; + e.click.pt.y = y; + w->wndproc(w, &e); +} + + +void DispatchMouseWheelEvent(Window *w, int wheel) +{ + + if (w->vscroll.count) { + int pos = clamp(w->vscroll.pos + wheel, 0, w->vscroll.count - w->vscroll.cap); + if (pos != w->vscroll.pos) { + w->vscroll.pos = pos; + SetWindowDirty(w); + } + } +} + + +void DrawOverlappedWindowForAll(int left, int top, int right, int bottom) +{ + Window *w; + DrawPixelInfo bk; + _cur_dpi = &bk; + + for(w=_windows; w!=_last_window; w++) { + if (right > w->left && + bottom > w->top && + left < w->left + w->width && + top < w->top + w->height) { + DrawOverlappedWindow(w, left, top, right, bottom); + } + } +} + +void DrawOverlappedWindow(Window *w, int left, int top, int right, int bottom) +{ + Window *v = w; + int x; + + while (++v != _last_window) { + if (right > v->left && + bottom > v->top && + left < v->left + v->width && + top < v->top + v->height) { + + if (left < (x=v->left)) { + DrawOverlappedWindow(w, left, top, x, bottom); + DrawOverlappedWindow(w, x, top, right, bottom); + return; + } + + if (right > (x=v->left + v->width)) { + DrawOverlappedWindow(w, left, top, x, bottom); + DrawOverlappedWindow(w, x, top, right, bottom); + return; + } + + if (top < (x=v->top)) { + DrawOverlappedWindow(w, left, top, right, x); + DrawOverlappedWindow(w, left, x, right, bottom); + return; + } + + if (bottom > (x=v->top + v->height)) { + DrawOverlappedWindow(w, left, top, right, x); + DrawOverlappedWindow(w, left, x, right, bottom); + return; + } + + return; + } + } + + { + DrawPixelInfo *dp = _cur_dpi; + dp->width = right - left; + dp->height = bottom - top; + dp->left = left - w->left; + dp->top = top - w->top; + dp->pitch = _screen.pitch; + dp->dst_ptr = _screen.dst_ptr + top * _screen.pitch + left; + dp->zoom = 0; + CallWindowEventNP(w, WE_PAINT); + } +} + +void CallWindowEventNP(Window *w, int event) +{ + WindowEvent e; + e.event = event; + w->wndproc(w, &e); +} + +void SetWindowDirty(Window *w) +{ + if (w == NULL) + return; + + SetDirtyBlocks(w->left, w->top, w->left + w->width, w->top + w->height); +} + +void DeleteWindow(Window *w) +{ + WindowClass wc; + WindowNumber wn; + ViewPort *vp; + Window *v; + int count; + + if (w == NULL) + return; + + if (_thd.place_mode != 0 && _thd.window_class == w->window_class && _thd.window_number == w->window_number) { + ResetObjectToPlace(); + } + + wc = w->window_class; + wn = w->window_number; + + CallWindowEventNP(w, WE_DESTROY); + + w = FindWindowById(wc, wn); + + vp = w->viewport; + w->viewport = NULL; + if (vp != NULL) { + _active_viewports &= ~(1 << (vp - _viewports)); + vp->width = 0; + } + + SetWindowDirty(w); + + v = --_last_window; + count = (byte*)v - (byte*)w; + memcpy(w, w + 1, count); +} + +Window *FindWindowById(WindowClass cls, WindowNumber number) +{ + Window *w; + + for(w=_windows; w!=_last_window; w++) { + if (w->window_class == cls && + w->window_number == number) { + return w; + } + } + + return NULL; +} + +void DeleteWindowById(WindowClass cls, WindowNumber number) +{ + DeleteWindow(FindWindowById(cls, number)); +} + +Window *BringWindowToFrontById(WindowClass cls, WindowNumber number) +{ + Window *w = FindWindowById(cls, number); + + if (w != NULL) { + w->flags4 |= WF_WHITE_BORDER_MASK; + SetWindowDirty(w); + BringWindowToFront(w); + } + + return w; +} + +Window *BringWindowToFront(Window *w) +{ + Window *v; + + v = _last_window; + do { + if (--v < _windows) + return w; + } while (v->window_class == WC_MAIN_TOOLBAR || v->window_class == WC_STATUS_BAR || v->window_class == WC_NEWS_WINDOW); + + if (w == v) + return w; + + assert(w < v); + + do { + memswap(w, w+1, sizeof(Window)); + w++; + } while (v != w); + + SetWindowDirty(w); + + return w; +} + +Window *AllocateWindow( + int x, + int y, + int width, + int height, + WindowProc *proc, + WindowClass cls, + const Widget *widget) +{ + Window *w; + +restart:; + w = _last_window; + + if (w >= endof(_windows)) { + for(w=_windows; ;w++) { + assert(w < _last_window); + + if (w->window_class != WC_MAIN_WINDOW && w->window_class != WC_MAIN_TOOLBAR && + w->window_class != WC_STATUS_BAR && w->window_class != WC_NEWS_WINDOW) { + + DeleteWindow(w); + goto restart; + } + } + } + + if (w != _windows && cls != WC_NEWS_WINDOW) { + Window *v; + + v = FindWindowById(WC_MAIN_TOOLBAR, 0); + if (v) { + memmove(v+1, v, (byte*)w - (byte*)v); + w = v; + } + + v = FindWindowById(WC_STATUS_BAR, 0); + if (v) { + memmove(v+1, v, (byte*)w - (byte*)v); + w = v; + } + } + + /* XXX: some more code here */ + w->window_class = cls; + w->flags4 = WF_WHITE_BORDER_MASK; + w->caption_color = 0xFF; + w->window_number = 0; + w->left = x; + w->top = y; + w->width = width; + w->height = height; + w->viewport = NULL; + w->desc_flags = 0; +// w->landscape_assoc = 0xFFFF; + w->wndproc = proc; + w->click_state = 0; + w->disabled_state = 0; + w->hidden_state = 0; +// w->unk22 = 0xFFFF; + w->vscroll.pos = 0; + w->vscroll.count = 0; + w->hscroll.pos = 0; + w->hscroll.count = 0; + w->widget = widget; + + ((uint32*)w->custom)[0] = 0; + ((uint32*)w->custom)[1] = 0; + ((uint32*)w->custom)[2] = 0; + ((uint32*)w->custom)[3] = 0; + + + _last_window++; + + SetWindowDirty(w); + + return w; +} + +Window *AllocateWindowAutoPlace2( + WindowClass exist_class, + WindowNumber exist_num, + int width, + int height, + WindowProc *proc, + WindowClass cls, + const Widget *widget) +{ + Window *w; + int x; + + w = FindWindowById(exist_class, exist_num); + if (w == NULL || w->left >= (_screen.width-20) || w->left <= -60 || w->top >= (_screen.height-20)) { + return AllocateWindowAutoPlace(width,height,proc,cls,widget); + } + + x = w->left; + if (x > _screen.width - width) + x = (_screen.width - width) - 20; + + return AllocateWindow(x+10,w->top+10,width,height,proc,cls,widget); +} + + +typedef struct SizeRect { + int left,top,width,height; +} SizeRect; + + +static SizeRect _awap_r; + +static bool IsGoodAutoPlace1(int left, int top) +{ + int right,bottom; + Window *w; + + _awap_r.left= left; + _awap_r.top = top; + right = _awap_r.width + left; + bottom = _awap_r.height + top; + + if (left < 0 || top < 22 || right > _screen.width || bottom > _screen.height) + return false; + + // Make sure it is not obscured by any window. + for(w=_windows; w!=_last_window; w++) { + if (w->window_class == WC_MAIN_WINDOW) + continue; + + if (right > w->left && + w->left + w->width > left && + bottom > w->top && + w->top + w->height > top) + return false; + } + + return true; +} + +static bool IsGoodAutoPlace2(int left, int top) +{ + int width,height; + Window *w; + + _awap_r.left= left; + _awap_r.top = top; + width = _awap_r.width; + height = _awap_r.height; + + if (left < -(width>>2) || left > _screen.width - (width>>1)) + return false; + if (top < 22 || top > _screen.height - (height>>2)) + return false; + + // Make sure it is not obscured by any window. + for(w=_windows; w!=_last_window; w++) { + if (w->window_class == WC_MAIN_WINDOW) + continue; + + if (left + width > w->left && + w->left + w->width > left && + top + height > w->top && + w->top + w->height > top) + return false; + } + + return true; +} + +Point GetAutoPlacePosition(int width, int height) { + Window *w; + Point pt; + + _awap_r.width = width; + _awap_r.height = height; + + if (IsGoodAutoPlace1(0, 24)) goto ok_pos; + + for(w=_windows; w!=_last_window; w++) { + if (w->window_class == WC_MAIN_WINDOW) + continue; + + if (IsGoodAutoPlace1(w->left+w->width+2,w->top)) goto ok_pos; + if (IsGoodAutoPlace1(w->left- width-2,w->top)) goto ok_pos; + if (IsGoodAutoPlace1(w->left,w->top+w->height+2)) goto ok_pos; + if (IsGoodAutoPlace1(w->left,w->top- height-2)) goto ok_pos; + if (IsGoodAutoPlace1(w->left+w->width+2,w->top+w->height-height)) goto ok_pos; + if (IsGoodAutoPlace1(w->left- width-2,w->top+w->height-height)) goto ok_pos; + if (IsGoodAutoPlace1(w->left+w->width-width,w->top+w->height+2)) goto ok_pos; + if (IsGoodAutoPlace1(w->left+w->width-width,w->top- height-2)) goto ok_pos; + } + + for(w=_windows; w!=_last_window; w++) { + if (w->window_class == WC_MAIN_WINDOW) + continue; + + if (IsGoodAutoPlace2(w->left+w->width+2,w->top)) goto ok_pos; + if (IsGoodAutoPlace2(w->left- width-2,w->top)) goto ok_pos; + if (IsGoodAutoPlace2(w->left,w->top+w->height+2)) goto ok_pos; + if (IsGoodAutoPlace2(w->left,w->top- height-2)) goto ok_pos; + } + + { + int left=0,top=24; + +restart:; + for(w=_windows; w!=_last_window; w++) { + if (w->left == left && w->top == top) { + left += 5; + top += 5; + goto restart; + } + } + + pt.x = left; + pt.y = top; + return pt; + } + +ok_pos:; + pt.x = _awap_r.left; + pt.y = _awap_r.top; + return pt; +} + +Window *AllocateWindowAutoPlace( + int width, + int height, + WindowProc *proc, + WindowClass cls, + const Widget *widget) { + + Point pt = GetAutoPlacePosition(width, height); + return AllocateWindow(pt.x, pt.y, width, height, proc, cls, widget); +} + +Window *AllocateWindowDescFront(const WindowDesc *desc, int value) +{ + Window *w; + + if (BringWindowToFrontById(desc->cls, value)) + return NULL; + w = AllocateWindowDesc(desc); + w->window_number = value; + return w; +} + +Window *AllocateWindowDesc(const WindowDesc *desc) +{ + Point pt; + Window *w; + + if (desc->parent_cls != WC_MAIN_WINDOW && + (w = FindWindowById(desc->parent_cls, _alloc_wnd_parent_num), _alloc_wnd_parent_num=0, w) != NULL && + w->left < _screen.width-20 && w->left > -60 && w->top < _screen.height-20) { + pt.x = w->left + 10; + if (pt.x > _screen.width + 10 - desc->width) + pt.x = (_screen.width + 10 - desc->width) - 20; + pt.y = w->top + 10; + } else { + pt.x = desc->left; + pt.y = desc->top; + if (pt.x == WDP_AUTO) { + pt = GetAutoPlacePosition(desc->width, desc->height); + } else { + if (pt.x == WDP_CENTER) pt.x = (_screen.width - desc->width) >> 1; + if (pt.y == WDP_CENTER) pt.y = (_screen.height - desc->height) >> 1; + } + } + + w = AllocateWindow(pt.x, pt.y, desc->width, desc->height, desc->proc, desc->cls, desc->widgets); + w->desc_flags = desc->flags; + return w; +} + +Window *FindWindowFromPt(int x, int y) +{ + Window *w; + + for(w=_last_window; w != _windows;) { + --w; + if (IS_INSIDE_1D(x, w->left, w->width) && + IS_INSIDE_1D(y, w->top, w->height)) + return w; + } + + return NULL; +} + + +void InitWindowSystem() +{ + memset(&_windows, 0, sizeof(_windows)); + _last_window = _windows; + memset(_viewports, 0, sizeof(_viewports)); + _active_viewports = 0; +} + +void DecreaseWindowCounters() +{ + Window *w; + + + for(w=_last_window; w != _windows;) { + --w; + // Unclick scrollbar buttons if they are pressed. + if (w->flags4 & (WF_SCROLL_DOWN | WF_SCROLL_UP)) { + w->flags4 &= ~(WF_SCROLL_DOWN | WF_SCROLL_UP); + SetWindowDirty(w); + } + CallWindowEventNP(w, WE_MOUSELOOP); + } + + for(w=_last_window; w != _windows;) { + --w; + + if (w->flags4&WF_TIMEOUT_MASK && !(--w->flags4&WF_TIMEOUT_MASK)) { + CallWindowEventNP(w, WE_TIMEOUT); + if (w->desc_flags & WDF_UNCLICK_BUTTONS) + UnclickWindowButtons(w); + } + } +} + +Window *GetCallbackWnd() +{ + return FindWindowById(_thd.window_class, _thd.window_number); +} + +void HandlePlacePresize() +{ + Window *w; + WindowEvent e; + + if (_special_mouse_mode != WSM_PRESIZE) + return; + + if ((w = GetCallbackWnd()) == NULL) + return; + + e.place.pt = GetTileBelowCursor(); + if (e.place.pt.x == -1) { + _thd.selend.x = -1; + return; + } + e.place.tile = TILE_FROM_XY(e.place.pt.x, e.place.pt.y); + e.event = WE_PLACE_PRESIZE; + w->wndproc(w, &e); +} + +bool HandleDragDrop() +{ + Window *w; + WindowEvent e; + + if (_special_mouse_mode != WSM_DRAGDROP) + return true; + + if (_left_button_down) + return false; + + w = GetCallbackWnd(); + + ResetObjectToPlace(); + + if (w) { + // send an event in client coordinates. + e.event = WE_DRAGDROP; + e.dragdrop.pt.x = _cursor.pos.x - w->left; + e.dragdrop.pt.y = _cursor.pos.y - w->top; + e.dragdrop.widget = GetWidgetFromPos(w, e.dragdrop.pt.x, e.dragdrop.pt.y); + w->wndproc(w, &e); + } + return false; +} + +bool HandlePopupMenu() +{ + Window *w; + WindowEvent e; + + if (!_popup_menu_active) + return true; + + w = FindWindowById(WC_TOOLBAR_MENU, 0); + if (w == NULL) { + _popup_menu_active = false; + return false; + } + + if (_left_button_down) { + e.event = WE_POPUPMENU_OVER; + e.popupmenu.pt = _cursor.pos; + w->wndproc(w, &e); + } else { + _popup_menu_active = false; + e.event = WE_POPUPMENU_SELECT; + e.popupmenu.pt = _cursor.pos; + w->wndproc(w, &e); + } + + return false; +} + +bool HandleWindowDragging() +{ + Window *w; + int x, y, t; + + // Get out immediately if no window is being dragged at all. + if (!_dragging_window) + return true; + + // Otherwise find the window... + for(w=_windows; w != _last_window; w++) { + if (w->flags4&(WF_DRAGGING|WF_SIZING)) { + + // Stop the dragging if the left mouse button was released + if (!_left_button_down) { + w->flags4 &= ~(WF_DRAGGING | WF_SIZING); + break; + } + + // Otherwise calculate the delta position. + x = _cursor.pos.x; + y = clamp2(_cursor.pos.y, 23, _screen.height-12); + t = _cursorpos_drag_start.x; _cursorpos_drag_start.x = x; x-=t; + t = _cursorpos_drag_start.y; _cursorpos_drag_start.y = y; y-=t; + + // No movement? + if (x == 0 && y == 0) + return false; + + // Mark the old position dirty + SetWindowDirty(w); + + if (w->flags4 & WF_SIZING) { + // Size the window + w->width += x; + w->height += y; + } else { + // Move the window and viewport + w->left += x; + w->top += y; + if (w->viewport) { + w->viewport->left += x; + w->viewport->top += y; + } + } + + // And also mark the new position dirty. + SetWindowDirty(w); + return false; + } + } + + _dragging_window = false; + return false; +} + +Window *StartWindowDrag(Window *w) +{ + w->flags4 |= WF_DRAGGING; + _dragging_window = true; + _cursorpos_drag_start = _cursor.pos; + w = BringWindowToFront(w); + DeleteWindowById(WC_DROPDOWN_MENU, 0); + return w; +} + +Window *StartWindowSizing(Window *w) +{ + w->flags4 |= WF_SIZING; + _dragging_window = true; + _cursorpos_drag_start = _cursor.pos; + w = BringWindowToFront(w); + DeleteWindowById(WC_DROPDOWN_MENU, 0); + return w; +} + + +bool HandleScrollbarScrolling() +{ + Window *w; + int i; + int pos; + Scrollbar *sb; + + // Get out quickly if no item is being scrolled + if (!_scrolling_scrollbar) + return true; + + // Find the scrolling window + for(w=_windows; w != _last_window; w++) { + if (w->flags4 & WF_SCROLL_MIDDLE) { + // Abort if no button is clicked any more. + if (!_left_button_down) { + w->flags4 &= ~WF_SCROLL_MIDDLE; + SetWindowDirty(w); + break; + } + + if (w->flags4 & WF_HSCROLL) { + sb = &w->hscroll; + i = _cursor.pos.x - _cursorpos_drag_start.x; + } else { + sb = &w->vscroll; + i = _cursor.pos.y - _cursorpos_drag_start.y; + } + + // Find the item we want to move to and make sure it's inside bounds. + pos = min(max(0, i + _scrollbar_start_pos) * sb->count / _scrollbar_size, max(0, sb->count - sb->cap)); + if (pos != sb->pos) { + sb->pos = pos; + SetWindowDirty(w); + } + return false; + } + } + + _scrolling_scrollbar = false; + return false; +} + +bool HandleViewportScroll() +{ + Window *w; + ViewPort *vp; + int dx,dy, x, y, sub; + + if (!_scrolling_viewport) + return true; + + if (!_right_button_down) { +stop_capt:; + _cursor.fix_at = false; + _scrolling_viewport = false; + return true; + } + + w = FindWindowFromPt(_cursor.pos.x, _cursor.pos.y); + if (w == NULL) goto stop_capt; + + if (w->window_class != WC_SMALLMAP) { + vp = IsPtInWindowViewport(w, _cursor.pos.x, _cursor.pos.y); + if (vp == NULL) + goto stop_capt; + + WP(w,vp_d).scrollpos_x += _cursor.delta.x << vp->zoom; + WP(w,vp_d).scrollpos_y += _cursor.delta.y << vp->zoom; + _cursor.delta.x = _cursor.delta.y = 0; + return false; + } else { + // scroll the smallmap ? + + _cursor.fix_at = true; + + dx = _cursor.delta.x; + dy = _cursor.delta.y; + + x = WP(w,smallmap_d).scroll_x; + y = WP(w,smallmap_d).scroll_y; + + sub = WP(w,smallmap_d).subscroll + dx; + + x -= (sub >> 2) << 4; + y += (sub >> 2) << 4; + sub &= 3; + + x += (dy >> 1) << 4; + y += (dy >> 1) << 4; + + if (dy & 1) { + x += 16; + sub += 2; + if (sub > 3) { + sub -= 4; + x -= 16; + y += 16; + } + } + + if (x < 16) { x = 16; sub = 0; } + if (x > (TILES_X-2)*16) { x = (TILES_X-2)*16; sub = 0; } + if (y < -1120) { y = -1120; sub = 0; } + if (y > (TILE_X_MAX-40) * 16) { y = (TILE_X_MAX-40) * 16; sub = 0; } + + WP(w,smallmap_d).scroll_x = x; + WP(w,smallmap_d).scroll_y = y; + WP(w,smallmap_d).subscroll = sub; + + _cursor.delta.x = _cursor.delta.y = 0; + + SetWindowDirty(w); + return false; + } +} + +static Window *MaybeBringWindowToFront(Window *w) +{ + Window *u; + + if (w->window_class == WC_MAIN_WINDOW || + w->window_class == WC_MAIN_TOOLBAR || + w->window_class == WC_STATUS_BAR || + w->window_class == WC_NEWS_WINDOW || + w->window_class == WC_TOOLTIPS || + w->window_class == WC_DROPDOWN_MENU) + return w; + + for(u=w; ++u != _last_window;) { + if (u->window_class == WC_MAIN_WINDOW || u->window_class==WC_MAIN_TOOLBAR || u->window_class==WC_STATUS_BAR || + u->window_class == WC_NEWS_WINDOW || u->window_class == WC_TOOLTIPS || u->window_class == WC_DROPDOWN_MENU) + continue; + + if (w->left + w->width <= u->left || + u->left + u->width <= w->left || + w->top + w->height <= u->top || + u->top + u->height <= w->top) + continue; + + return BringWindowToFront(w); + } + + return w; +} + +static void HandleKeypress(uint32 key) +{ + Window *w; + WindowEvent we; + + // Setup event + we.keypress.event = WE_KEYPRESS; + we.keypress.ascii = key & 0xFF; + we.keypress.keycode = key >> 16; + we.keypress.cont = true; + + // Call the event, start with the uppermost window. + for(w=_last_window; w != _windows;) { + --w; + w->wndproc(w, &we); + if (!we.keypress.cont) + break; + } +} + +extern void UpdateTileSelection(); +extern bool VpHandlePlaceSizingDrag(); + +void MouseLoop() +{ + int x,y; + Window *w; + ViewPort *vp; + int click; + int mousewheel; + + _current_player = _local_player; + + // Handle pressed keys + if (_pressed_key) { + uint32 key = _pressed_key; _pressed_key = 0; + HandleKeypress(key); + } + + // Mouse event? + click = 0; + if (_left_button_down && !_left_button_clicked) { + _left_button_clicked = true; + click = 1; + } else if (_right_button_clicked) { + _right_button_clicked = false; + click = 2; + } + + mousewheel = 0; + if (_cursor.wheel) { + mousewheel = _cursor.wheel; + _cursor.wheel = 0; + } + + DecreaseWindowCounters(); + HandlePlacePresize(); + UpdateTileSelection(); + if (!VpHandlePlaceSizingDrag()) + return; + + if (!HandleDragDrop()) + return; + + if (!HandlePopupMenu()) + return; + + if (!HandleWindowDragging()) + return; + + if (!HandleScrollbarScrolling()) + return; + + if (!HandleViewportScroll()) + return; + + x = _cursor.pos.x; + y = _cursor.pos.y; + + + if (click == 0 && mousewheel == 0) { + if (_patches.autoscroll && _game_mode != GM_MENU) { + w = FindWindowFromPt(x, y); + if (w == NULL || w->flags4 & WF_DISABLE_VP_SCROLL ) return; + vp = IsPtInWindowViewport(w, x, y); + if (vp) { + x -= vp->left; + y -= vp->top; + //here allows scrolling in both x and y axis +#define scrollspeed 3 + if (x-15<0) { WP(w,vp_d).scrollpos_x += (x-15) * scrollspeed << vp->zoom; } + else if (15-(vp->width-x) > 0) { WP(w,vp_d).scrollpos_x += (15-(vp->width-x))*scrollspeed << vp->zoom; } + if (y-15<0) { WP(w,vp_d).scrollpos_y += (y-15)*scrollspeed << vp->zoom; } + else if (15-(vp->height-y) > 0) { WP(w,vp_d).scrollpos_y += (15-(vp->height-y))*scrollspeed << vp->zoom; } +#undef scrollspeed + } + } + return; + } + + w = FindWindowFromPt(x, y); + if (w == NULL) + return; + w = MaybeBringWindowToFront(w); + vp = IsPtInWindowViewport(w, x, y); + if (vp != NULL) { + if (_game_mode == GM_MENU) + return; + + if (mousewheel && !(w->flags4 & WF_DISABLE_VP_SCROLL)) { + ZoomInOrOutToCursor(mousewheel < 0); + } + + if (click == 1) { + if (_thd.place_mode != 0 && + _cursor.sprite != 0x2CF && + _pause != 0 && + !_patches.build_in_pause) + return; + + if (_thd.place_mode == 0) { + HandleViewportClicked(vp, x, y); + } else { + PlaceObject(); + } + } else if (click == 2) { + if (!(w->flags4 & WF_DISABLE_VP_SCROLL)) { + _scrolling_viewport = true; + _cursor.fix_at = true; + } + } + } else { + if (mousewheel) + DispatchMouseWheelEvent(w, mousewheel); + + if (click == 1) + DispatchLeftClickEvent(w, x - w->left, y - w->top); + else if (click == 2) + DispatchRightClickEvent(w, x - w->left, y - w->top); + } +} + +static int _we4_timer; + +extern uint32 _pixels_redrawn; + +void UpdateWindows() +{ + Window *w; + int t; + + + if ((t=_we4_timer+1) >= 100) { + for(w = _last_window; w != _windows;) { + w--; + CallWindowEventNP(w, WE_4); + } + t = 0; + } + _we4_timer = t; + + for(w = _last_window; w != _windows;) { + w--; + if (w->flags4 & WF_WHITE_BORDER_MASK) { + w->flags4 -= WF_WHITE_BORDER_ONE; + if (!(w->flags4 & WF_WHITE_BORDER_MASK)) { + SetWindowDirty(w); + } + } + } + + DrawDirtyBlocks(); + + for(w = _windows; w!=_last_window; w++) { + if (w->viewport != NULL) + UpdateViewportPosition(w); + } + // Redraw mouse cursor in case it was hidden + DrawMouseCursor(); +} + + +int GetMenuItemIndex(Window *w, int x, int y) +{ + if ((x -= w->left) >= 0 && x < w->width && (y -= w->top + 1) >= 0) { + y /= 10; + + if (y < WP(w,menu_d).item_count) + return y; + } + return -1; +} + +void InvalidateWindow(byte cls, WindowNumber number) +{ + Window *w; + + for(w=_windows; w!=_last_window; w++) { + if (w->window_class==cls && w->window_number==number) + SetWindowDirty(w); + } +} + +void InvalidateWidget(Window *w, byte widget_index) +{ + const Widget *wi = &w->widget[widget_index]; +// if (wi->left != -2) { + SetDirtyBlocks( + w->left + wi->left, + w->top + wi->top, + w->left + wi->right + 1, + w->top + wi->bottom + 1); +// } +} + +void InvalidateWindowWidget(byte cls, WindowNumber number, byte widget_index) +{ + Window *w; + + for(w=_windows; w!=_last_window; w++) { + if (w->window_class==cls && w->window_number==number) { + InvalidateWidget(w, widget_index); + } + } +} + +void InvalidateWindowClasses(byte cls) +{ + Window *w; + for(w=_windows; w!=_last_window; w++) { + if (w->window_class==cls) + SetWindowDirty(w); + } +} + + +void CallWindowTickEvent() +{ + Window *w; + for(w=_last_window; w != _windows;) { + --w; + CallWindowEventNP(w, WE_TICK); + } +} + +void DeleteNonVitalWindows() +{ + Window *w; + for(w=_windows; w!=_last_window;) { + if (w->window_class != WC_MAIN_WINDOW && + w->window_class != WC_SELECT_GAME && + w->window_class != WC_MAIN_TOOLBAR && + w->window_class != WC_STATUS_BAR && + w->window_class != WC_TOOLBAR_MENU && + w->window_class != WC_TOOLTIPS) { + DeleteWindow(w); + w = _windows; + } else { + w++; + } + } +} + +void RelocateAllWindows(int neww, int newh) +{ + Window *w; + + for(w=_windows; w!= _last_window ;w++) { + int left, top; + + if (w->window_class == WC_MAIN_WINDOW) { + ViewPort *vp = w->viewport; + vp->width = w->width = neww; + vp->height = w->height = newh; + vp->virtual_width = neww << vp->zoom; + vp->virtual_height = newh << vp->zoom; + continue; // don't modify top,left + } + + if (w->window_class == WC_MAIN_TOOLBAR) { + top = w->top; + left = (neww - w->width) >> 1; + } else if (w->window_class == WC_SELECT_GAME || w->window_class == WC_GAME_OPTIONS || w->window_class == WC_NETWORK_WINDOW){ + top = (newh - w->height) >> 1; + left = (neww - w->width) >> 1; + } else if (w->window_class == WC_NEWS_WINDOW) { + top = newh - w->height; + left = (neww - w->width) >> 1; + } else if (w->window_class == WC_STATUS_BAR) { + top = newh - w->height; + left = (neww - w->width) >> 1; + } else { + left = w->left; + if (left + (w->width>>1) >= neww) left = neww - w->width; + top = w->top; + if (top + (w->height>>1) >= newh) top = newh - w->height; + } + + if (w->viewport) { + w->viewport->left += left - w->left; + w->viewport->top += top - w->top; + } + + w->left = left; + w->top = top; + } +} + -- cgit v1.2.3-54-g00ecf