1103 lines
34 KiB
C
1103 lines
34 KiB
C
#include "wmwindow.h"
|
|
#include "array.h"
|
|
#include "font.h"
|
|
|
|
|
|
#define ICON_SIZE 32
|
|
#define WIDGET_SIZE 20
|
|
#define SCROLL_SPEED_SLOW 5 // ***TODO*** Move into GUI after we get scrollbar widgets.
|
|
#define SCROLL_SPEED_FAST 25
|
|
|
|
|
|
uint8_t __MAGIC_WINDOW = 0;
|
|
|
|
|
|
static WindowT **_windowList = NULL;
|
|
static WindowT *_windowTop = NULL;
|
|
static int16_t _iconCount = 0;
|
|
|
|
|
|
static void windowCache(WindowT *w, uint8_t redrawWindow);
|
|
static void windowDestroy(struct WidgetS *widget, ...);
|
|
static void windowPaint(struct WidgetS *widget, ...);
|
|
static void windowScrollHorizontalHandler(EventT *e, WindowT *w);
|
|
static void windowScrollVerticalHandler(EventT *e, WindowT *w);
|
|
|
|
|
|
static void windowCache(WindowT *w, uint8_t redrawWindow) {
|
|
char c;
|
|
int16_t i;
|
|
int16_t x1;
|
|
int16_t y1;
|
|
int16_t x2;
|
|
int16_t y2;
|
|
int16_t tx1;
|
|
int16_t tx2;
|
|
int16_t ty2;
|
|
int16_t originalX;
|
|
int16_t originalY;
|
|
double d;
|
|
RectT originalBounds;
|
|
ColorT titleBackgroundColor;
|
|
ColorT widgetColor;
|
|
SurfaceT *target = surfaceGet();
|
|
|
|
// Move the window to 0,0 to draw it into it's own surface.
|
|
originalX = w->base.r.x;
|
|
originalY = w->base.r.y;
|
|
w->base.r.x = 0;
|
|
w->base.r.y = 0;
|
|
|
|
// Do we have a cached surface already?
|
|
if (w->cached) {
|
|
// Did the size change?
|
|
if ((surfaceWidthGet(w->cached) != w->base.r.w) || (surfaceHeightGet(w->cached) != w->base.r.h)) {
|
|
// Yeah. We will recreate it.
|
|
surfaceDestroy(&w->cached);
|
|
}
|
|
}
|
|
// Do we need to create a surface?
|
|
if (!w->cached) {
|
|
w->cached = surfaceCreate(w->base.r.w, w->base.r.h);
|
|
}
|
|
|
|
// Draw into cache.
|
|
surfaceSet(w->cached);
|
|
|
|
if (redrawWindow) {
|
|
// Determine some colors.
|
|
titleBackgroundColor = (w == _windowTop) ? GUI_DARKGRAY : GUI_LIGHTGRAY;
|
|
widgetColor = (w == _windowTop) ? GUI_LIGHTGRAY : GUI_DARKGRAY;
|
|
|
|
// Get ready!
|
|
x1 = w->base.r.x;
|
|
y1 = w->base.r.y;
|
|
x2 = w->base.r.x + w->base.r.w - 1;
|
|
y2 = w->base.r.y + w->base.r.h - 1;
|
|
|
|
// Draw border.
|
|
surfaceBoxHighlight(x1, y1, x2, y2, GUI_WHITE, GUI_BLACK);
|
|
x1++; y1++; x2--; y2--;
|
|
for (i=0; i<3; i++) {
|
|
surfaceBox(x1, y1, x2, y2, GUI_LIGHTGRAY);
|
|
x1++; y1++; x2--; y2--;
|
|
}
|
|
surfaceBoxHighlight(x1, y1, x2, y2, GUI_BLACK, GUI_WHITE);
|
|
x1++; y1++; x2--; y2--;
|
|
|
|
// Do we need a titlebar?
|
|
if (w->title || w->flags & WIN_CLOSE || w->flags & WIN_MAXIMIZE || w->flags & WIN_MINIMIZE) {
|
|
tx1 = x1;
|
|
tx2 = x2;
|
|
ty2 = y1 + WIDGET_SIZE;
|
|
|
|
// Close box?
|
|
if (w->flags & WIN_CLOSE) {
|
|
tx1 += WIDGET_SIZE;
|
|
w->close.x = x1;
|
|
w->close.y = y1;
|
|
w->close.x2 = tx1 - 1;
|
|
w->close.y2 = ty2 - 1;
|
|
surfaceBoxFilled(w->close.x + 1, w->close.y + 1, w->close.x2 - 1, w->close.y2 - 1, titleBackgroundColor);
|
|
surfaceBoxHighlight(w->close.x + 3, w->close.y + 8, w->close.x2 - 3, w->close.y2 - 8, GUI_WHITE, widgetColor);
|
|
surfaceBoxHighlight(w->close.x, w->close.y, w->close.x2, w->close.y2, GUI_WHITE, GUI_BLACK);
|
|
} else {
|
|
w->close.x = w->close.y = w->close.x2 = w->close.y2 = 0;
|
|
}
|
|
|
|
// Maximize box?
|
|
if (w->flags & WIN_MAXIMIZE) {
|
|
tx2 -= WIDGET_SIZE;
|
|
w->maximize.x = tx2 + 1;
|
|
w->maximize.y = y1;
|
|
w->maximize.x2 = tx2 + WIDGET_SIZE;
|
|
w->maximize.y2 = ty2 - 1;
|
|
surfaceBoxFilled(w->maximize.x + 1, w->maximize.y + 1, w->maximize.x2 - 1, w->maximize.y2 - 1, titleBackgroundColor);
|
|
surfaceLine(w->maximize.x + 4, w->maximize.y + 10, w->maximize.x + 10, w->maximize.y + 4, GUI_WHITE);
|
|
surfaceLine(w->maximize.x + 4, w->maximize.y + 10, w->maximize.x + 10, w->maximize.y2 - 3, GUI_WHITE);
|
|
surfaceLine(w->maximize.x2 - 3, w->maximize.y + 10, w->maximize.x2 - 9, w->maximize.y + 4, widgetColor);
|
|
surfaceLine(w->maximize.x2 - 3, w->maximize.y + 10, w->maximize.x2 - 9, w->maximize.y2 - 3, widgetColor);
|
|
surfaceBoxHighlight(w->maximize.x, w->maximize.y, w->maximize.x2, w->maximize.y2, GUI_WHITE, GUI_BLACK);
|
|
} else {
|
|
w->maximize.x = w->maximize.y = w->maximize.x2 = w->maximize.y2 = 0;
|
|
}
|
|
|
|
// Minimize box?
|
|
if (w->flags & WIN_MINIMIZE) {
|
|
tx2 -= WIDGET_SIZE;
|
|
w->minimize.x = tx2 + 1;
|
|
w->minimize.y = y1;
|
|
w->minimize.x2 = tx2 + WIDGET_SIZE;
|
|
w->minimize.y2 = ty2 - 1;
|
|
surfaceBoxFilled(w->minimize.x + 1, w->minimize.y + 1, w->minimize.x2 - 1, w->minimize.y2 - 1, titleBackgroundColor);
|
|
surfaceBoxHighlight(w->minimize.x + 7, w->minimize.y + 7, w->minimize.x2 - 7, w->minimize.y2 - 7, GUI_WHITE, widgetColor);
|
|
surfaceBoxHighlight(w->minimize.x, w->minimize.y, w->minimize.x2, w->minimize.y2, GUI_WHITE, GUI_BLACK);
|
|
} else {
|
|
w->minimize.x = w->minimize.y = w->minimize.x2 = w->maximize.y2 = 0;
|
|
}
|
|
|
|
// Draw titlebar background.
|
|
w->titlebar.x = tx1;
|
|
w->titlebar.y = y1;
|
|
w->titlebar.x2 = tx2;
|
|
w->titlebar.y2 = ty2 - 1;
|
|
surfaceBoxFilled(w->titlebar.x + 1, w->titlebar.y + 1, w->titlebar.x2 - 1, w->titlebar.y2 - 1, titleBackgroundColor);
|
|
if (w->title) {
|
|
// Prepare font. Don't allow color changes in titles.
|
|
fontSet(__guiFontVGA8x16);
|
|
fontColorSet(GUI_WHITE, titleBackgroundColor);
|
|
fontModsEnabledSet(0);
|
|
// How many characters do we have room for?
|
|
i = ((w->titlebar.x2 - w->titlebar.x) >> 3) - 2;
|
|
// Does the title fit?
|
|
if ((int16_t)strlen(w->title) <= i) {
|
|
// Render entire title.
|
|
fontRender(w->title, w->titlebar.x + 12, w->titlebar.y + 2);
|
|
} else {
|
|
// Render partial title.
|
|
c = w->title[i];
|
|
w->title[i] = 0;
|
|
fontRender(w->title, w->titlebar.x + 12, w->titlebar.y + 2);
|
|
w->title[i] = c;
|
|
}
|
|
}
|
|
surfaceBoxHighlight(w->titlebar.x, w->titlebar.y, w->titlebar.x2, w->titlebar.y2, GUI_WHITE, GUI_BLACK);
|
|
|
|
y1 += WIDGET_SIZE;
|
|
} else {
|
|
w->close.x = w->close.y = w->close.x2 = w->close.y2 = 0;
|
|
w->maximize.x = w->maximize.y = w->maximize.x2 = w->maximize.y2 = 0;
|
|
w->minimize.x = w->minimize.y = w->minimize.x2 = w->maximize.y2 = 0;
|
|
w->titlebar.x = w->titlebar.y = w->titlebar.x2 = w->titlebar.y2 = 0;
|
|
}
|
|
|
|
// Vertical Scroll Bar?
|
|
if (w->flags & WIN_SCROLL_V) {
|
|
w->scrollv.x2 = x2;
|
|
w->scrollv.x = w->scrollv.x2 - (WIDGET_SIZE - 1);
|
|
w->scrollv.y = y1;
|
|
w->scrollv.y2 = y2;
|
|
// Draw scroll bar.
|
|
surfaceBoxFilled(w->scrollv.x + 1, w->scrollv.y + 1, w->scrollv.x2 - 1, w->scrollv.y2 - 1, titleBackgroundColor);
|
|
surfaceBoxHighlight(w->scrollv.x, w->scrollv.y, w->scrollv.x2, w->scrollv.y2, GUI_WHITE, GUI_BLACK);
|
|
surfaceLineH(w->scrollv.x + 1, w->scrollv.x2, w->scrollv.y + (WIDGET_SIZE - 1), GUI_BLACK);
|
|
surfaceLineH(w->scrollv.x + 1, w->scrollv.x2, w->scrollv.y2 - (WIDGET_SIZE - 1), GUI_WHITE);
|
|
// Prepare font.
|
|
fontSet(__guiFontVGA8x8);
|
|
fontColorSet(widgetColor, titleBackgroundColor);
|
|
// Draw arrows.
|
|
fontRender("\x1e", w->scrollv.x + 7, w->scrollv.y + 7);
|
|
fontRender("\x1f", w->scrollv.x + 7, w->scrollv.y2 - 12);
|
|
|
|
x2 -= (WIDGET_SIZE - 1);
|
|
} else {
|
|
w->scrollv.x = w->scrollv.y = w->scrollv.x2 = w->scrollv.y2 = 0;
|
|
}
|
|
|
|
// Horizontal Scroll Bar?
|
|
if (w->flags & WIN_SCROLL_H) {
|
|
w->scrollh.x = x1;
|
|
w->scrollh.x2 = x2;
|
|
w->scrollh.y2 = y2;
|
|
w->scrollh.y = w->scrollh.y2 - (WIDGET_SIZE - 1);
|
|
// Draw scroll bar.
|
|
surfaceBoxFilled(w->scrollh.x + 1, w->scrollh.y + 1, w->scrollh.x2 - 1, w->scrollh.y2 - 1, titleBackgroundColor);
|
|
surfaceBoxHighlight(w->scrollh.x, w->scrollh.y, w->scrollh.x2, w->scrollh.y2, GUI_WHITE, GUI_BLACK);
|
|
surfaceLineV(w->scrollh.x + (WIDGET_SIZE - 1), w->scrollh.y + 1, w->scrollh.y2, GUI_BLACK);
|
|
surfaceLineV(w->scrollh.x2 - (WIDGET_SIZE - 1), w->scrollh.y + 1, w->scrollh.y2, GUI_WHITE);
|
|
// If we have both horizontal and vertical scroll bars, we need to fix a shadow.
|
|
if (w->flags & WIN_SCROLL_V) {
|
|
surfaceLineV(w->scrollh.x2 - 1, w->scrollh.y, w->scrollh.y2, GUI_BLACK);
|
|
surfaceLineV(w->scrollh.x2, w->scrollh.y, w->scrollh.y2, GUI_WHITE);
|
|
}
|
|
// Prepare font.
|
|
fontSet(__guiFontVGA8x8);
|
|
fontColorSet(widgetColor, titleBackgroundColor);
|
|
// Draw arrows.
|
|
fontRender("\x11", w->scrollh.x + 7, w->scrollh.y + 7);
|
|
fontRender("\x10", w->scrollh.x2 - 12, w->scrollh.y + 7);
|
|
|
|
y2 -= (WIDGET_SIZE - 1);
|
|
} else {
|
|
w->scrollh.x = w->scrollh.y = w->scrollh.x2 = w->scrollh.y2 = 0;
|
|
}
|
|
|
|
// Find content area.
|
|
w->bounds.x = x1;
|
|
w->bounds.y = y1;
|
|
w->bounds.x2 = x2;
|
|
w->bounds.y2 = y2;
|
|
|
|
// Do we have content yet?
|
|
if (w->content) {
|
|
|
|
// Vertical Scroll Bar Thumb?
|
|
if (w->flags & WIN_SCROLL_V) {
|
|
// Distance between arrow buttons on scroll bar.
|
|
i = w->scrollv.y2 - w->scrollv.y - (WIDGET_SIZE * 2 - 2) - 2;
|
|
// Percentage to scale content height to scroll bar height.
|
|
d = (double)i / (double)surfaceHeightGet(w->content);
|
|
// Find position and size of thumb.
|
|
w->thumbv.x = w->scrollv.x + 1;
|
|
w->thumbv.x2 = w->scrollv.x2 - 1;
|
|
w->thumbv.y = w->scrollv.y + WIDGET_SIZE + (w->offset.y * d);
|
|
w->thumbv.y2 = w->thumbv.y + ((w->bounds.y2 - w->bounds.y) * d);
|
|
// Clamp overflow due to doubles and my off-by-one brain.
|
|
if (w->thumbv.y2 >= w->thumbv.y + i - 1) w->thumbv.y2 = w->thumbv.y + i - 1;
|
|
// Draw thumb.
|
|
surfaceBoxFilled(w->thumbv.x + 1, w->thumbv.y + 1, w->thumbv.x2 - 1, w->thumbv.y2 - 1, widgetColor);
|
|
surfaceBoxHighlight(w->thumbv.x, w->thumbv.y, w->thumbv.x2, w->thumbv.y2, GUI_WHITE, GUI_BLACK);
|
|
} else {
|
|
w->thumbv.x = w->thumbv.y = w->thumbv.x2 = w->thumbv.y2 = 0;
|
|
}
|
|
|
|
// Horizontal Scroll Bar Thumb?
|
|
if (w->flags & WIN_SCROLL_H) {
|
|
// Distance between arrow buttons on scroll bar.
|
|
i = w->scrollh.x2 - w->scrollh.x - (WIDGET_SIZE * 2 - 2) - 2;
|
|
// Percentage to scale content width to scroll bar width.
|
|
d = (double)i / (double)surfaceWidthGet(w->content);
|
|
// Find position and size of thumb.
|
|
w->thumbh.x = w->scrollh.x + WIDGET_SIZE + (w->offset.x * d);
|
|
w->thumbh.x2 = w->thumbh.x + ((w->bounds.x2 - w->bounds.x) * d);
|
|
w->thumbh.y = w->scrollh.y + 1;
|
|
w->thumbh.y2 = w->scrollh.y2 - 1;
|
|
// Clamp overflow due to doubles and my off-by-one brain.
|
|
if (w->thumbh.x2 >= w->thumbh.x + i - 1) w->thumbh.x2 = w->thumbh.x + i - 1;
|
|
// Draw thumb.
|
|
surfaceBoxFilled(w->thumbh.x + 1, w->thumbh.y + 1, w->thumbh.x2 - 1, w->thumbh.y2 - 1, widgetColor);
|
|
surfaceBoxHighlight(w->thumbh.x, w->thumbh.y, w->thumbh.x2, w->thumbh.y2, GUI_WHITE, GUI_BLACK);
|
|
} else {
|
|
w->thumbh.x = w->thumbh.y = w->thumbh.x2 = w->thumbh.y2 = 0;
|
|
}
|
|
|
|
} else { // Do we have content yet?
|
|
w->thumbv.x = w->thumbv.y = w->thumbv.x2 = w->thumbv.y2 = 0;
|
|
w->thumbh.x = w->thumbh.y = w->thumbh.x2 = w->thumbh.y2 = 0;
|
|
}
|
|
|
|
// Resize handle.
|
|
if (w->flags & WIN_RESIZE) {
|
|
w->resize1.x2 = w->base.r.x + w->base.r.w - 2;
|
|
w->resize1.x = w->resize1.x2 - 3;
|
|
w->resize1.y2 = w->base.r.y + w->base.r.h;
|
|
w->resize1.y = w->resize1.y2 - (WIDGET_SIZE + 5);
|
|
surfaceLineH(w->resize1.x, w->resize1.x2, w->resize1.y, GUI_BLACK);
|
|
surfaceLineH(w->resize1.x, w->resize1.x2, w->resize1.y + 1, GUI_WHITE);
|
|
w->resize2.x2 = w->base.r.x + w->base.r.w;
|
|
w->resize2.x = w->resize2.x2 - (WIDGET_SIZE + 5);
|
|
w->resize2.y2 = w->base.r.y + w->base.r.h - 2;
|
|
w->resize2.y = w->resize2.y2 - 3;
|
|
surfaceLineV(w->resize2.x, w->resize2.y, w->resize2.y2, GUI_BLACK);
|
|
surfaceLineV(w->resize2.x + 1, w->resize2.y, w->resize2.y2, GUI_WHITE);
|
|
} else {
|
|
w->resize1.x = w->resize1.y = w->resize1.x2 = w->resize1.y2 = 0;
|
|
w->resize2.x = w->resize2.y = w->resize2.x2 = w->resize2.y2 = 0;
|
|
}
|
|
|
|
} else { // Redraw window.
|
|
|
|
// Since we didn't calculate them above, adjust bounds for content blit.
|
|
originalBounds = w->bounds;
|
|
w->bounds.x -= originalX;
|
|
w->bounds.y -= originalY;
|
|
w->bounds.x2 -= originalX;
|
|
w->bounds.y2 -= originalY;
|
|
}
|
|
|
|
// Blit contents.
|
|
if (w->content) surfaceBlit(w->bounds.x, w->bounds.y, w->offset.x, w->offset.y, w->bounds.x2 - w->bounds.x, w->bounds.y2 - w->bounds.y, w->content);
|
|
|
|
// Fixup all the widget coordinates.
|
|
if (redrawWindow) {
|
|
windowMove(w, originalX, originalY);
|
|
} else {
|
|
w->bounds = originalBounds;
|
|
w->base.r.x = originalX;
|
|
w->base.r.y = originalY;
|
|
}
|
|
|
|
surfaceSet(target);
|
|
}
|
|
|
|
|
|
#include "image.h"
|
|
// Passing "flags" as a default int provides proper alignment for the following va_args list.
|
|
WindowT *windowCreate(uint16_t x, uint16_t y, uint16_t w, uint16_t h, char *title, int flags, ...) {
|
|
int16_t width;
|
|
int16_t height;
|
|
va_list args;
|
|
WindowT *win = NULL;
|
|
SurfaceT *t = surfaceGet();
|
|
|
|
NEW(WindowT, win);
|
|
memset(win, 0, sizeof(WindowT));
|
|
guiWidgetBaseSet((WidgetT *)win, __MAGIC_WINDOW, x, y, w, h);
|
|
win->title = strdup(title);
|
|
win->flags = (uint8_t)flags;
|
|
|
|
/*
|
|
// ***DEBUG*** Hackery to get contents before we have widgets.
|
|
static uint8_t image = 1;
|
|
static char name[16];
|
|
windowCache(win, 1);
|
|
width = win->bounds.x2 - win->bounds.x;
|
|
height = win->bounds.y2 - win->bounds.y;
|
|
guiWidgetDirtySet(W(win), 1);
|
|
sprintf(name, "back%d.png", image);
|
|
win->content = imageLoad(name);
|
|
if (image == 3) {
|
|
win->offset.x = 100;//(surfaceWidthGet(win->content) - width) * 0.5;
|
|
win->offset.y = 100;//(surfaceHeightGet(win->content) - height) * 0.5;
|
|
}
|
|
image++;
|
|
*/
|
|
|
|
// If the window is resizable, we need to get two more arguments for the content size.
|
|
if (win->flags & WIN_RESIZE) {
|
|
va_start(args, flags);
|
|
width = va_arg(args, int);
|
|
height = va_arg(args, int);
|
|
va_end(args);
|
|
} else {
|
|
// Use whatever the default content area is. This causes an extra draw on create. Oh well.
|
|
windowCache(win, 1);
|
|
width = win->bounds.x2 - win->bounds.x;
|
|
height = win->bounds.y2 - win->bounds.y;
|
|
guiWidgetDirtySet(W(win), 1);
|
|
}
|
|
// Create content surface and clear it.
|
|
win->content = surfaceCreate(width, height);
|
|
surfaceSet(win->content);
|
|
surfaceClear(GUI_LIGHTGRAY);
|
|
surfaceSet(t);
|
|
|
|
// Add to window list.
|
|
arrput(_windowList, win);
|
|
|
|
// Focus us.
|
|
windowFocusSet(win);
|
|
|
|
return win;
|
|
}
|
|
|
|
|
|
static void windowDestroy(struct WidgetS *widget, ...) {
|
|
uint16_t i;
|
|
uint16_t c;
|
|
WindowT *window = (WindowT *)widget;
|
|
|
|
// Remove it from the window list, if it exists there.
|
|
for (i=0; i<arrlen(_windowList); i++) {
|
|
if (window == _windowList[i]) {
|
|
arrdel(_windowList, i);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Was it the focused window?
|
|
if (window == _windowTop) {
|
|
// Find new topmost window on next call to focus.
|
|
_windowTop = NULL;
|
|
}
|
|
// Free the title.
|
|
if (window->title) DEL(window->title);
|
|
// Free children.
|
|
for (c=0; c<arrlen(window->children); c++) guiWidgetDestroy(window->children[c]);
|
|
arrfree(window->children);
|
|
// Free cached surface.
|
|
if (window->cached) surfaceDestroy(&window->cached);
|
|
// Free content surface.
|
|
if (window->content) surfaceDestroy(&window->content);
|
|
// Delete the window.
|
|
DEL(window);
|
|
// Fixup focus.
|
|
windowFocusSet(NULL);
|
|
}
|
|
|
|
|
|
void windowFocusSet(WindowT *win) {
|
|
int16_t i;
|
|
|
|
// Do we have a focused window at the moment?
|
|
if (!_windowTop || !win) {
|
|
_windowTop = NULL;
|
|
// If there's a list of windows, use the topmost non-minimized.
|
|
if (arrlen(_windowList) > 0) {
|
|
// Work backwards through the window list.
|
|
i = arrlen(_windowList) - 1;
|
|
for (; i>=0; i--) {
|
|
if (_windowList[i]->flags & WIN_IS_ICON) {
|
|
// Minimized window. Skip it.
|
|
continue;
|
|
} else {
|
|
// Open window. Use as new top.
|
|
_windowTop = _windowList[i];
|
|
guiWidgetDirtySet(W(_windowTop), 1);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Did they even pass in a window? If not, we're just intended to fixup _windowTop.
|
|
if (!win) return;
|
|
|
|
// Were we already the topmost window?
|
|
if (win == _windowTop) return;
|
|
|
|
// Is this window minimized?
|
|
if (win->flags & WIN_IS_ICON) {
|
|
// Can't receive focus - find new top.
|
|
windowFocusSet(NULL);
|
|
return;
|
|
}
|
|
|
|
// Mark old focus and new focus dirty to repaint title bar.
|
|
guiWidgetDirtySet(W(win), 1);
|
|
guiWidgetDirtySet(W(_windowTop), 1);
|
|
|
|
// Change who has focus.
|
|
_windowTop = win;
|
|
|
|
// Reorder window list.
|
|
i = arrlen(_windowList) - 2;
|
|
if (i >= 0) {
|
|
for (; i>=0; i--) {
|
|
if (_windowList[i] == win) {
|
|
arrdel(_windowList, i);
|
|
arrput(_windowList, win);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void windowMaximizeRestore(WindowT *win) {
|
|
int16_t i;
|
|
|
|
// Are we maximized?
|
|
if (win->flags & WIN_IS_MAX) {
|
|
|
|
// Restore to previous size.
|
|
win->flags &= ~WIN_IS_MAX;
|
|
win->base.r = win->restore;
|
|
win->offset = win->restoreOffset;
|
|
|
|
} else { // Maximized?
|
|
|
|
// Maximize window. Reposition if needed.
|
|
win->flags |= WIN_IS_MAX;
|
|
|
|
// Remember current size and position.
|
|
win->restore = win->base.r;
|
|
win->restoreOffset = win->offset;
|
|
|
|
// Scroll contents to home.
|
|
win->offset.x = 0;
|
|
win->offset.y = 0;
|
|
|
|
// Expand to full contents.
|
|
win->base.r.w = (win->base.r.w - (win->bounds.x2 - win->bounds.x) + surfaceWidthGet(win->content));
|
|
win->base.r.h = (win->base.r.h - (win->bounds.y2 - win->bounds.y) + surfaceHeightGet(win->content));
|
|
|
|
// Does this go off the screen to the right?
|
|
if (win->base.r.x + win->base.r.w >= videoDisplayWidthGet()) {
|
|
// Can we move it left to fit?
|
|
i = videoDisplayWidthGet() - (win->base.r.x + win->base.r.w);
|
|
if (i <= win->base.r.x) {
|
|
// Yes, go left!
|
|
win->base.r.x += i;
|
|
} else {
|
|
// Nope. Go all the way left and resize to fit on desktop.
|
|
win->base.r.x = 0;
|
|
win->base.r.w = videoDisplayWidthGet();
|
|
}
|
|
}
|
|
|
|
// Does this go off the screen to the bottom?
|
|
if (win->base.r.y + win->base.r.h >= videoDisplayHeightGet()) {
|
|
// Can we move it up to fit?
|
|
i = videoDisplayHeightGet() - (win->base.r.y + win->base.r.h);
|
|
if (i <= win->base.r.y) {
|
|
// Yes, go up!
|
|
win->base.r.y += i;
|
|
} else {
|
|
// Nope. Go all the way up and resize to fit on desktop.
|
|
win->base.r.y = 0;
|
|
win->base.r.h = videoDisplayHeightGet();
|
|
}
|
|
}
|
|
|
|
} // Maximized?
|
|
|
|
// Update.
|
|
windowCache(win, 1);
|
|
}
|
|
|
|
|
|
void windowMinimize(WindowT *win) {
|
|
// Minimize.
|
|
win->flags |= WIN_IS_ICON;
|
|
// Find topmost non-minimized window.
|
|
windowFocusSet(NULL);
|
|
}
|
|
|
|
|
|
void windowMove(WindowT *w, uint16_t x, uint16_t y) {
|
|
int16_t dx = x - w->base.r.x;
|
|
int16_t dy = y - w->base.r.y;
|
|
|
|
// This is all because we draw the window at 0,0 in order to cache it.
|
|
// To keep the coordinates correct, we have to adjust them all when
|
|
// the window is moved.
|
|
|
|
if (w->title || w->flags & WIN_CLOSE || w->flags & WIN_MAXIMIZE || w->flags & WIN_MINIMIZE) {
|
|
if (w->flags & WIN_CLOSE) {
|
|
w->close.x += dx;
|
|
w->close.y += dy;
|
|
w->close.x2 += dx;
|
|
w->close.y2 += dy;
|
|
}
|
|
|
|
if (w->flags & WIN_MAXIMIZE) {
|
|
w->maximize.x += dx;
|
|
w->maximize.y += dy;
|
|
w->maximize.x2 += dx;
|
|
w->maximize.y2 += dy;
|
|
}
|
|
|
|
if (w->flags & WIN_MINIMIZE) {
|
|
w->minimize.x += dx;
|
|
w->minimize.y += dy;
|
|
w->minimize.x2 += dx;
|
|
w->minimize.y2 += dy;
|
|
}
|
|
|
|
w->titlebar.x += dx;
|
|
w->titlebar.y += dy;
|
|
w->titlebar.x2 += dx;
|
|
w->titlebar.y2 += dy;
|
|
}
|
|
|
|
if (w->flags & WIN_SCROLL_V) {
|
|
w->scrollv.x += dx;
|
|
w->scrollv.y += dy;
|
|
w->scrollv.x2 += dx;
|
|
w->scrollv.y2 += dy;
|
|
w->thumbv.x += dx;
|
|
w->thumbv.y += dy;
|
|
w->thumbv.x2 += dx;
|
|
w->thumbv.y2 += dy;
|
|
}
|
|
|
|
if (w->flags & WIN_SCROLL_H) {
|
|
w->scrollh.x += dx;
|
|
w->scrollh.y += dy;
|
|
w->scrollh.x2 += dx;
|
|
w->scrollh.y2 += dy;
|
|
w->thumbh.x += dx;
|
|
w->thumbh.y += dy;
|
|
w->thumbh.x2 += dx;
|
|
w->thumbh.y2 += dy;
|
|
}
|
|
|
|
if (w->flags & WIN_RESIZE) {
|
|
w->resize1.x += dx;
|
|
w->resize1.y += dy;
|
|
w->resize1.x2 += dx;
|
|
w->resize1.y2 += dy;
|
|
w->resize2.x += dx;
|
|
w->resize2.y += dy;
|
|
w->resize2.x2 += dx;
|
|
w->resize2.y2 += dy;
|
|
}
|
|
|
|
w->bounds.x += dx;
|
|
w->bounds.y += dy;
|
|
w->bounds.x2 += dx;
|
|
w->bounds.y2 += dy;
|
|
|
|
w->base.r.x = x;
|
|
w->base.r.y = y;
|
|
}
|
|
|
|
|
|
static void windowPaint(struct WidgetS *widget, ...) {
|
|
int16_t x;
|
|
int16_t y;
|
|
int16_t px;
|
|
int16_t py;
|
|
int16_t xi;
|
|
int16_t yi;
|
|
int16_t xc;
|
|
int16_t yc;
|
|
WindowT *w = (WindowT *)widget;
|
|
SurfaceT *t = surfaceGet();
|
|
|
|
// Are any child widgets dirty?
|
|
y = 0;
|
|
for (x=0; x<arrlen(w->children); x++) {
|
|
if (w->children[x]->dirty) {
|
|
y = 1;
|
|
if (w->children[x]->reg->paint) {
|
|
surfaceSet(w->content);
|
|
w->children[x]->reg->paint(w->children[x]);
|
|
}
|
|
}
|
|
}
|
|
surfaceSet(t);
|
|
|
|
// Does the window itself need redrawn?
|
|
if (guiWidgetDirtyGet(widget)) {
|
|
guiWidgetDirtySet(widget, 0);
|
|
x = 1;
|
|
} else {
|
|
x = 0;
|
|
}
|
|
|
|
// Did a widget or the window need redrawn?
|
|
if (x || y) windowCache(w, x);
|
|
|
|
// Are we minimized?
|
|
if (w->flags & WIN_IS_ICON) {
|
|
// Draw iconized version of contents. There are too many counters here but it's the only way it worked reliably.
|
|
yi = (surfaceHeightGet(w->content) - 1) / ICON_SIZE;
|
|
xi = (surfaceWidthGet(w->content) - 1) / ICON_SIZE;
|
|
py = videoDisplayHeightGet() - ICON_SIZE;
|
|
y = 0;
|
|
x = 0;
|
|
for (yc=0; yc<ICON_SIZE; yc++) {
|
|
y += yi;
|
|
px = (ICON_SIZE + 1) * _iconCount;
|
|
for (xc=0; xc<ICON_SIZE; xc++) {
|
|
x += xi;
|
|
surfacePixelSet(px++, py, surfacePixelGet(w->content, x, y));
|
|
}
|
|
py++;
|
|
}
|
|
_iconCount++;
|
|
} else {
|
|
// By now we have a valid cached window. Blit it.
|
|
surfaceBlit(w->base.r.x, w->base.r.y, 0, 0, 0, 0, w->cached);
|
|
}
|
|
}
|
|
|
|
|
|
RegisterT *windowRegister(uint8_t magic) {
|
|
static RegisterT reg = {
|
|
"Window",
|
|
NULL, // Click event is special for windows.
|
|
windowDestroy, // Destroy.
|
|
windowPaint, // Paint.
|
|
NULL // Unregister.
|
|
};
|
|
|
|
// One-time widget startup code.
|
|
__MAGIC_WINDOW = magic;
|
|
|
|
return ®
|
|
}
|
|
|
|
|
|
void windowResize(WindowT *win, uint16_t width, uint16_t height) {
|
|
|
|
int16_t delta;
|
|
|
|
// Too small?
|
|
if (width < (WIDGET_SIZE * 4) + 15) width = (WIDGET_SIZE * 4) + 15;
|
|
if (height < (WIDGET_SIZE * 4) + 15) height = (WIDGET_SIZE * 4) + 15;
|
|
|
|
// Too big?
|
|
if (win->bounds.w - win->bounds.x + (width - win->base.r.w) + win->offset.x > surfaceWidthGet(win->content)) {
|
|
// Do we have room to scroll content into view?
|
|
if (win->offset.x > 0) {
|
|
delta = width - win->base.r.w;
|
|
if (delta > win->offset.x) delta = win->offset.x;
|
|
win->offset.x -= delta;
|
|
}
|
|
width = (win->base.r.w - (win->bounds.x2 - win->bounds.x) - win->offset.x + surfaceWidthGet(win->content));
|
|
}
|
|
if (win->bounds.h - win->bounds.y + (height - win->base.r.h) + win->offset.y > surfaceHeightGet(win->content)) {
|
|
// Do we have room to scroll content into view?
|
|
if (win->offset.y > 0) {
|
|
delta = height - win->base.r.h;
|
|
if (delta > win->offset.y) delta = win->offset.y;
|
|
win->offset.y -= delta;
|
|
}
|
|
height = (win->base.r.h - (win->bounds.y2 - win->bounds.y) - win->offset.y + surfaceHeightGet(win->content));
|
|
}
|
|
|
|
// Did the size change?
|
|
if (win->base.r.w != width || win->base.r.h !=height) {
|
|
// Yes! If we were maximized, clear it - can't restore after resizing.
|
|
win->flags &= ~WIN_IS_MAX;
|
|
|
|
// Do resize.
|
|
win->base.r.w = width;
|
|
win->base.r.h =height;
|
|
windowCache(win, 1);
|
|
}
|
|
}
|
|
|
|
|
|
static void windowScrollHorizontalHandler(EventT *e, WindowT *w) {
|
|
|
|
// Clicking in left arrow?
|
|
if (e->x <= w->scrollh.x + WIDGET_SIZE) {
|
|
// Move content left.
|
|
w->offset.x -= SCROLL_SPEED_SLOW;
|
|
// Clip.
|
|
if (w->offset.x < 0) w->offset.x = 0;
|
|
// Update.
|
|
windowCache(w, 1);
|
|
return;
|
|
}
|
|
|
|
// Clicking in right arrow?
|
|
if (e->x >= w->scrollh.x2 - WIDGET_SIZE) {
|
|
// Move content right.
|
|
w->offset.x += SCROLL_SPEED_SLOW;
|
|
// Clip.
|
|
if (w->offset.x > surfaceWidthGet(w->content) - (w->bounds.x2 - w->bounds.x)) w->offset.x = surfaceWidthGet(w->content) - (w->bounds.x2 - w->bounds.x);
|
|
// Update.
|
|
windowCache(w, 1);
|
|
return;
|
|
}
|
|
|
|
// Clicking left of thumb? Also fakes dragging.
|
|
if (e->x < w->thumbh.x) {
|
|
// Move content left.
|
|
w->offset.x -= SCROLL_SPEED_FAST;
|
|
// Clip.
|
|
if (w->offset.x < 0) w->offset.x = 0;
|
|
// Update.
|
|
windowCache(w, 1);
|
|
return;
|
|
}
|
|
|
|
// Clicking right of thumb? Also fakes dragging.
|
|
if (e->x > w->thumbh.x2) {
|
|
// Move content right.
|
|
w->offset.x += SCROLL_SPEED_FAST;
|
|
// Clip.
|
|
if (w->offset.x > surfaceWidthGet(w->content) - (w->bounds.x2 - w->bounds.x)) w->offset.x = surfaceWidthGet(w->content) - (w->bounds.x2 - w->bounds.x);
|
|
// Update.
|
|
windowCache(w, 1);
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
static void windowScrollVerticalHandler(EventT *e, WindowT *w) {
|
|
|
|
// Clicking in up arrow?
|
|
if (e->y <= w->scrollv.y + WIDGET_SIZE) {
|
|
// Move content up.
|
|
w->offset.y -= SCROLL_SPEED_SLOW;
|
|
// Clip.
|
|
if (w->offset.y < 0) w->offset.y = 0;
|
|
// Update.
|
|
windowCache(w, 1);
|
|
return;
|
|
}
|
|
|
|
// Clicking in down arrow?
|
|
if (e->y >= w->scrollv.y2 - WIDGET_SIZE) {
|
|
// Move content down.
|
|
w->offset.y += SCROLL_SPEED_SLOW;
|
|
// Clip.
|
|
if (w->offset.y > surfaceHeightGet(w->content) - (w->bounds.y2 - w->bounds.y)) w->offset.y = surfaceHeightGet(w->content) - (w->bounds.y2 - w->bounds.y);
|
|
// Update.
|
|
windowCache(w, 1);
|
|
return;
|
|
}
|
|
|
|
// Clicking above thumb? Also fakes dragging.
|
|
if (e->y < w->thumbv.y) {
|
|
// Move content up.
|
|
w->offset.y -= SCROLL_SPEED_FAST;
|
|
// Clip.
|
|
if (w->offset.y < 0) w->offset.y = 0;
|
|
// Update.
|
|
windowCache(w, 1);
|
|
return;
|
|
}
|
|
|
|
// Clicking below thumb? Also fakes dragging.
|
|
if (e->y > w->thumbv.y2) {
|
|
// Move content down.
|
|
w->offset.y += SCROLL_SPEED_FAST;
|
|
// Clip.
|
|
if (w->offset.y > surfaceHeightGet(w->content) - (w->bounds.y2 - w->bounds.y)) w->offset.y = surfaceHeightGet(w->content) - (w->bounds.y2 - w->bounds.y);
|
|
// Update.
|
|
windowCache(w, 1);
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
void windowWidgetAdd(WindowT *window, WidgetT *widget) {
|
|
arrput(window->children, widget);
|
|
}
|
|
|
|
|
|
void windowWidgetRemove(WindowT *window, WidgetT *widget) {
|
|
uint16_t i;
|
|
|
|
for (i=0; i<arrlen(window->children); i++) {
|
|
if (window->children[i] == widget) {
|
|
arrdel(window->children, i);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void wmShutdown(void) {
|
|
uint16_t i;
|
|
|
|
for (i=0; i<arrlen(_windowList); i++) guiWidgetDestroy((WidgetT *)_windowList[i]);
|
|
arrfree(_windowList);
|
|
}
|
|
|
|
|
|
void wmStartup(void) {
|
|
// Nada
|
|
}
|
|
|
|
|
|
void wmUpdate(EventT *event) {
|
|
int16_t i;
|
|
int16_t x2;
|
|
int16_t y2;
|
|
uint8_t onResize = 0;
|
|
WidgetT *widget;
|
|
WindowT *win = NULL;
|
|
static uint8_t resizing = 0;
|
|
static PointT resizeOffset = { 0 };
|
|
static uint8_t dragging = 0;
|
|
static PointT dragOffset = { 0 };
|
|
|
|
// Do we have windows?
|
|
if (arrlen(_windowList) > 0) {
|
|
|
|
// Mouse is always the default pointer unless something changes it for this frame.
|
|
guiMousePointerSet(MOUSE_POINTER);
|
|
|
|
// Paint all windows.
|
|
_iconCount = 0;
|
|
for (i=0; i<arrlen(_windowList); i++) {
|
|
surfaceSet(__guiBackBuffer);
|
|
widget = (WidgetT *)_windowList[i];
|
|
widget->reg->paint(widget);
|
|
}
|
|
|
|
// Get top window.
|
|
win = _windowTop;
|
|
|
|
// If we found a window, get right/bottom.
|
|
if (win) {
|
|
x2 = win->base.r.x + win->base.r.w - 1;
|
|
y2 = win->base.r.y + win->base.r.h - 1;
|
|
} else {
|
|
x2 = 0;
|
|
y2 = 0;
|
|
}
|
|
|
|
// Wrap left button processing with a 'for' so we can 'break' out of it.
|
|
for (;;) {
|
|
|
|
// Does the topmost window have a resize?
|
|
if (win && win->flags & WIN_RESIZE) {
|
|
// Are we over the resize of the topmost window?
|
|
if ((event->x <= win->resize1.x2 && event->x >= win->resize1.x && event->y <= win->resize1.y2 && event->y >= win->resize1.y) ||
|
|
(event->x <= win->resize2.x2 && event->x >= win->resize2.x && event->y <= win->resize2.y2 && event->y >= win->resize2.y) ||
|
|
resizing) {
|
|
onResize = 1;
|
|
guiMousePointerSet(MOUSE_RESIZE);
|
|
}
|
|
}
|
|
|
|
// Is the left mouse button down?
|
|
if (event->buttons & BUTTON_LEFT) {
|
|
|
|
/*
|
|
// DEBUG - draw active regions.
|
|
surfaceSet(__guiBackBuffer);
|
|
surfaceBox(win->base.r.x, win->base.r.y, x2, y2, GUI_YELLOW);
|
|
surfaceBox(win->bounds.x, win->bounds.y, win->bounds.x2, win->bounds.y2, GUI_CYAN);
|
|
surfaceBox(win->close.x, win->close.y, win->close.x2, win->close.y2, GUI_LIGHTBLUE);
|
|
surfaceBox(win->titlebar.x, win->titlebar.y, win->titlebar.x2, win->titlebar.y2, GUI_LIGHTCYAN);
|
|
surfaceBox(win->minimize.x, win->minimize.y, win->minimize.x2, win->minimize.y2, GUI_LIGHTGREEN);
|
|
surfaceBox(win->maximize.x, win->maximize.y, win->maximize.x2, win->maximize.y2, GUI_RED);
|
|
surfaceBox(win->scrollv.x, win->scrollv.y, win->scrollv.x2, win->scrollv.y2, GUI_BLUE);
|
|
surfaceBox(win->scrollh.x, win->scrollh.y, win->scrollh.x2, win->scrollh.y2, GUI_BROWN);
|
|
*/
|
|
|
|
// Are we currently dragging?
|
|
if (dragging) {
|
|
|
|
// Move window to new mouse location.
|
|
windowMove(win, event->x - dragOffset.x, event->y - dragOffset.y);
|
|
break;
|
|
|
|
} else { // Dragging.
|
|
|
|
if (resizing) {
|
|
// If they try to resize outside the window bounds, cancel it.
|
|
if (event->x < win->base.r.x || event->y < win->base.r.y) break;
|
|
// Resize it.
|
|
windowResize(win, event->x - resizeOffset.x, event->y - resizeOffset.y);
|
|
break;
|
|
|
|
} else { // Resizing.
|
|
|
|
// Did the button just go down?
|
|
if (event->flags & EVENT_FLAG_LEFT_DOWN) {
|
|
|
|
// Are we on the topmost window?
|
|
if (win && event->x <= x2 && event->x >= win->base.r.x && event->y <= y2 && event->y >= win->base.r.y) {
|
|
|
|
// Are we on the resizing area?
|
|
if (onResize) {
|
|
resizing = 1;
|
|
resizeOffset.x = event->x - win->base.r.w;
|
|
resizeOffset.y = event->y - win->base.r.h;
|
|
break;
|
|
}
|
|
|
|
// Are we inside the window content? Most likely, check first.
|
|
if (event->x <= win->bounds.x2 && event->x >= win->bounds.x && event->y <= win->bounds.y2 && event->y >= win->bounds.y) {
|
|
//***TODO*** Send to window for processing.
|
|
}
|
|
|
|
// Are we inside the close button? Does not include button frame on purpose.
|
|
if (win->flags & WIN_CLOSE && event->x < win->close.x2 && event->x > win->close.x && event->y < win->close.y2 && event->y > win->close.y) {
|
|
//***TODO*** Close.
|
|
}
|
|
|
|
// Are we inside the title bar to begin dragging? Does not include titlebar frame on purpose.
|
|
if (event->x < win->titlebar.x2 && event->x > win->titlebar.x && event->y < win->titlebar.y2 && event->y > win->titlebar.y) {
|
|
dragging = 1;
|
|
dragOffset.x = event->x - win->base.r.x;
|
|
dragOffset.y = event->y - win->base.r.y;
|
|
break;
|
|
}
|
|
|
|
// Are we inside the minimize button? Does not include button frame on purpose.
|
|
if (win->flags & WIN_MINIMIZE &&event->x < win->minimize.x2 && event->x > win->minimize.x && event->y < win->minimize.y2 && event->y > win->minimize.y) {
|
|
windowMinimize(win);
|
|
break;
|
|
}
|
|
|
|
// Are we inside the maximize button? Does not include button frame on purpose.
|
|
if (win->flags & WIN_MAXIMIZE &&event->x < win->maximize.x2 && event->x > win->maximize.x && event->y < win->maximize.y2 && event->y > win->maximize.y) {
|
|
windowMaximizeRestore(win);
|
|
break;
|
|
}
|
|
|
|
// Are we inside the vertical scroll bar? Does not include frame on purpose.
|
|
if (win->flags & WIN_SCROLL_V &&event->x < win->scrollv.x2 && event->x > win->scrollv.x && event->y < win->scrollv.y2 && event->y > win->scrollv.y) {
|
|
windowScrollVerticalHandler(event, win);
|
|
break;
|
|
}
|
|
|
|
// Are we inside the horizontal scroll bar? Does not include frame on purpose.
|
|
if (win->flags & WIN_SCROLL_H &&event->x < win->scrollh.x2 && event->x > win->scrollh.x && event->y < win->scrollh.y2 && event->y > win->scrollh.y) {
|
|
windowScrollHorizontalHandler(event, win);
|
|
break;
|
|
}
|
|
|
|
} else { // On topmost window.
|
|
|
|
// Not over topmost window. Search backwards to find first window we're inside.
|
|
i = arrlen(_windowList) - 1;
|
|
if (i >= 0) {
|
|
for (; i>=0; i--) {
|
|
win = _windowList[i];
|
|
// Is this the current window?
|
|
if (win == _windowTop) continue;
|
|
// Is this window minimized?
|
|
if (win->flags & WIN_IS_ICON) continue;
|
|
// Get right/bottom of window.
|
|
x2 = win->base.r.x + win->base.r.w - 1;
|
|
y2 = win->base.r.y + win->base.r.h - 1;
|
|
// Inside this window?
|
|
if (event->x <= x2 && event->x >= win->base.r.x && event->y <= y2 && event->y >= win->base.r.y) {
|
|
// Bring this window forward.
|
|
windowFocusSet(win);
|
|
// If we happened to be in the title bar, go ahead and start dragging. Does not include titlebar frame on purpose.
|
|
if (event->x < win->titlebar.x2 && event->x > win->titlebar.x && event->y < win->titlebar.y2 && event->y > win->titlebar.y) {
|
|
dragging = 1;
|
|
dragOffset.x = event->x - win->base.r.x;
|
|
dragOffset.y = event->y - win->base.r.y;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
} // On topmost window.
|
|
|
|
// Do we have minimized windows?
|
|
if (_iconCount > 0) {
|
|
// Are we inside the minimized icons area?
|
|
if (event->x < (ICON_SIZE + 1) * _iconCount && event->y >= videoDisplayHeightGet() - ICON_SIZE) {
|
|
// Figure out which icon we're over.
|
|
x2 = 0;
|
|
for (i=0; i<arrlen(_windowList); i++) {
|
|
if (_windowList[i]->flags & WIN_IS_ICON) {
|
|
x2 += ICON_SIZE;
|
|
// This window?
|
|
if (event->x < x2) {
|
|
// Restore it and stop looking for icons.
|
|
_windowList[i]->flags &= ~WIN_IS_ICON;
|
|
windowFocusSet(_windowList[i]);
|
|
break;
|
|
}
|
|
// Next! (Skips pixel between icons.)
|
|
x2++;
|
|
}
|
|
}
|
|
} // Minimized windows?
|
|
}
|
|
|
|
} else { // Button just went down / button being held down.
|
|
|
|
// Are we inside the vertical scroll bar? Does not include frame on purpose.
|
|
if (win->flags & WIN_SCROLL_V &&event->x < win->scrollv.x2 && event->x > win->scrollv.x && event->y < win->scrollv.y2 && event->y > win->scrollv.y) {
|
|
windowScrollVerticalHandler(event, win);
|
|
break;
|
|
}
|
|
|
|
// Are we inside the horizontal scroll bar? Does not include frame on purpose.
|
|
if (win->flags & WIN_SCROLL_H &&event->x < win->scrollh.x2 && event->x > win->scrollh.x && event->y < win->scrollh.y2 && event->y > win->scrollh.y) {
|
|
windowScrollHorizontalHandler(event, win);
|
|
break;
|
|
}
|
|
|
|
} // Left button held down.
|
|
|
|
} // Resizing.
|
|
|
|
} // Dragging.
|
|
|
|
} else { // Left mouse button.
|
|
|
|
// Left mouse not down.
|
|
|
|
// Can no longer be dragging.
|
|
dragging = 0;
|
|
|
|
// Can no longer be resizing.
|
|
resizing = 0;
|
|
}
|
|
|
|
break;
|
|
} // Left button processing.
|
|
|
|
} // Do we have windows?
|
|
|
|
}
|