mirror of
https://github.com/JGRennison/OpenTTD-patches.git
synced 2024-11-06 03:20:28 +00:00
46af99b8c0
-Feature: With the sticky windows on and some unfortunate resizing of your game it the 'close' button might go outside of the playing field, making it impossible to close. Added an option to the Options menu that closes all windows, even if they are stickified ("Close ALL windows")
537 lines
15 KiB
C
537 lines
15 KiB
C
#include "stdafx.h"
|
|
#include "ttd.h"
|
|
#include "table/strings.h"
|
|
#include "window.h"
|
|
#include "gui.h"
|
|
#include "station.h"
|
|
#include "gfx.h"
|
|
#include "player.h"
|
|
#include "town.h"
|
|
#include "command.h"
|
|
|
|
static void StationsWndShowStationRating(int x, int y, int type, uint acceptance, int rating)
|
|
{
|
|
static const byte _rating_colors[NUM_CARGO] = {152,32,15,174,208,194,191,55,184,10,191,48};
|
|
int color = _rating_colors[type];
|
|
uint w;
|
|
|
|
if (acceptance > 575)
|
|
acceptance = 575;
|
|
|
|
acceptance = (acceptance + 7) >> 3;
|
|
|
|
/* draw cargo */
|
|
if ( (w=acceptance>>3) != 0) {
|
|
GfxFillRect(x, y, x+w-1, y+6, color);
|
|
x += w;
|
|
}
|
|
|
|
if ( (w=acceptance&7) != 0) {
|
|
if (w==7) w--;
|
|
GfxFillRect(x, y+(w-1), x, y+6, color);
|
|
}
|
|
|
|
x -= (acceptance>>3);
|
|
|
|
DrawString(x+1, y, _cargoc.names_short[type], 0x10);
|
|
|
|
/* draw green/red ratings bar */
|
|
GfxFillRect(x+1, y+8, x+7, y+8, 0xB8);
|
|
|
|
rating = (rating >> 5);
|
|
|
|
if (rating != 0) {
|
|
GfxFillRect(x+1, y+8, x+rating, y+8, 0xD0);
|
|
}
|
|
}
|
|
|
|
static SortStruct _station_sort[lengthof(_stations)];
|
|
static uint16 _num_station_sort[MAX_PLAYERS];
|
|
|
|
static char _bufcache[64];
|
|
static uint16 _last_station_idx;
|
|
|
|
static int CDECL StationNameSorter(const void *a, const void *b)
|
|
{
|
|
char buf1[64];
|
|
Station *st;
|
|
const SortStruct *cmp1 = (const SortStruct*)a;
|
|
const SortStruct *cmp2 = (const SortStruct*)b;
|
|
|
|
st = DEREF_STATION(cmp1->index);
|
|
SetDParam(0, st->town->townnametype);
|
|
SetDParam(1, st->town->townnameparts);
|
|
GetString(buf1, st->string_id);
|
|
|
|
if ( cmp2->index != _last_station_idx) {
|
|
_last_station_idx = cmp2->index;
|
|
st = DEREF_STATION(cmp2->index);
|
|
SetDParam(0, st->town->townnametype);
|
|
SetDParam(1, st->town->townnameparts);
|
|
GetString(_bufcache, st->string_id);
|
|
}
|
|
|
|
return strcmp(buf1, _bufcache); // sort by name
|
|
}
|
|
|
|
static void GlobalSortStationList()
|
|
{
|
|
const Station *st;
|
|
uint32 n = 0;
|
|
uint16 *i;
|
|
|
|
// reset #-of stations to 0 because ++ is used for value-assignment
|
|
for (i = _num_station_sort; i != endof(_num_station_sort); i++) {*i = 0;}
|
|
|
|
FOR_ALL_STATIONS(st) {
|
|
if(st->xy && st->owner != OWNER_NONE) {
|
|
_station_sort[n].index = st->index;
|
|
_station_sort[n++].owner = st->owner;
|
|
_num_station_sort[st->owner]++; // add number of stations of player
|
|
}
|
|
}
|
|
|
|
// create cumulative station-ownership
|
|
// stations are stored as a cummulative index, eg 25, 41, 43. This means
|
|
// Player0: 25; Player1: (41-25) 16; Player2: (43-41) 2
|
|
for (i = &_num_station_sort[1]; i != endof(_num_station_sort); i++) {*i += *(i-1);}
|
|
|
|
qsort(_station_sort, n, sizeof(_station_sort[0]), GeneralOwnerSorter); // sort by owner
|
|
|
|
// since indexes are messed up after adding/removing a station, mark all lists dirty
|
|
memset(_station_sort_dirty, true, sizeof(_station_sort_dirty));
|
|
_global_station_sort_dirty = false;
|
|
|
|
DEBUG(misc, 1) ("Resorting global station list...");
|
|
}
|
|
|
|
static void MakeSortedStationList(byte owner)
|
|
{
|
|
SortStruct *firstelement;
|
|
uint32 n = 0;
|
|
|
|
if (owner == 0) { // first element starts at 0th element and has n elements as described above
|
|
firstelement = &_station_sort[0];
|
|
n = _num_station_sort[0];
|
|
} else { // nth element starts at the end of the previous one, and has n elements as described above
|
|
firstelement = &_station_sort[_num_station_sort[owner-1]];
|
|
n = _num_station_sort[owner] - _num_station_sort[owner-1];
|
|
}
|
|
|
|
_last_station_idx = 0; // used for "cache" in namesorting
|
|
qsort(firstelement, n, sizeof(_station_sort[0]), StationNameSorter); // sort by name
|
|
|
|
_station_sort_dirty[owner] = false;
|
|
|
|
DEBUG(misc, 1) ("Resorting Stations list player %d...", owner+1);
|
|
}
|
|
|
|
static void PlayerStationsWndProc(Window *w, WindowEvent *e)
|
|
{
|
|
switch(e->event) {
|
|
case WE_PAINT: {
|
|
uint32 i;
|
|
const byte window_number = (byte)w->window_number;
|
|
|
|
// resort station window if stations have been added/removed
|
|
if (_global_station_sort_dirty)
|
|
GlobalSortStationList();
|
|
|
|
if (_station_sort_dirty[window_number]) { // resort in case of a station rename.
|
|
MakeSortedStationList(window_number);
|
|
}
|
|
|
|
// stations are stored as a cummulative index, eg 25, 41, 43. This means
|
|
// Player0: 25; Player1: (41-25) 16; Player2: (43-41) 2 stations
|
|
i = (window_number == 0) ? 0 : _num_station_sort[window_number-1];
|
|
SetVScrollCount(w, _num_station_sort[window_number] - i);
|
|
|
|
/* draw widgets, with player's name in the caption */
|
|
{
|
|
Player *p = DEREF_PLAYER(window_number);
|
|
SetDParam(0, p->name_1);
|
|
SetDParam(1, p->name_2);
|
|
SetDParam(2, w->vscroll.count);
|
|
DrawWindowWidgets(w);
|
|
}
|
|
|
|
{
|
|
byte p = 0;
|
|
Station *st;
|
|
int x,xb = 2;
|
|
int y = 16; // offset from top of widget
|
|
int j;
|
|
|
|
if (w->vscroll.count == 0) { // player has no stations
|
|
DrawString(xb, y, STR_304A_NONE, 0);
|
|
return;
|
|
}
|
|
|
|
i += w->vscroll.pos; // offset from sorted station list of current player
|
|
assert(i < _num_station_sort[window_number]); // at least one station must exist
|
|
|
|
while (i < _num_station_sort[window_number]) { // do until max number of stations of owner
|
|
st = DEREF_STATION(_station_sort[i].index);
|
|
|
|
assert(st->xy && st->owner == window_number);
|
|
|
|
SetDParam(0, st->index);
|
|
SetDParam(1, st->facilities);
|
|
x = DrawString(xb, y, STR_3049_0, 0) + 5;
|
|
|
|
// show cargo waiting and station ratings
|
|
for(j=0; j!=NUM_CARGO; j++) {
|
|
int acc = (st->goods[j].waiting_acceptance & 0xFFF);
|
|
if (acc != 0) {
|
|
StationsWndShowStationRating(x, y, j, acc, st->goods[j].rating);
|
|
x += 10;
|
|
}
|
|
}
|
|
y += 10;
|
|
i++; // next station
|
|
if (++p == w->vscroll.cap) { break;} // max number of stations in 1 window
|
|
}
|
|
}
|
|
} break;
|
|
case WE_CLICK: {
|
|
switch(e->click.widget) {
|
|
case 3: {
|
|
uint32 id_v = (e->click.pt.y - 15) / 10;
|
|
|
|
if (id_v >= w->vscroll.cap) { return;} // click out of bounds
|
|
|
|
id_v += w->vscroll.pos;
|
|
|
|
{
|
|
const byte owner = (byte)w->window_number;
|
|
Station *st;
|
|
id_v += (owner == 0) ? 0 : _num_station_sort[owner - 1]; // first element in list
|
|
|
|
if (id_v >= _num_station_sort[owner]) { return;} // click out of station bound
|
|
|
|
st = DEREF_STATION(_station_sort[id_v].index);
|
|
|
|
assert(st->xy && st->owner == owner);
|
|
|
|
ScrollMainWindowToTile(st->xy);
|
|
}
|
|
} break;
|
|
}
|
|
} break;
|
|
|
|
case WE_4:
|
|
WP(w,plstations_d).refresh_counter++;
|
|
if (WP(w,plstations_d).refresh_counter==5) {
|
|
WP(w,plstations_d).refresh_counter = 0;
|
|
SetWindowDirty(w);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
static const Widget _player_stations_widgets[] = {
|
|
{ WWT_CLOSEBOX, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
|
|
{ WWT_CAPTION, 14, 11, 345, 0, 13, STR_3048_STATIONS, STR_018C_WINDOW_TITLE_DRAG_THIS},
|
|
{ WWT_STICKYBOX, 14, 346, 357, 0, 13, 0x0, STR_STICKY_BUTTON},
|
|
{ WWT_PANEL, 14, 0, 346, 14, 137, 0x0, STR_3057_STATION_NAMES_CLICK_ON},
|
|
{ WWT_SCROLLBAR, 14, 347, 357, 14, 137, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
|
|
{ WIDGETS_END},
|
|
};
|
|
|
|
static const WindowDesc _player_stations_desc = {
|
|
-1, -1, 358, 138,
|
|
WC_STATION_LIST,0,
|
|
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON,
|
|
_player_stations_widgets,
|
|
PlayerStationsWndProc
|
|
};
|
|
|
|
|
|
void ShowPlayerStations(int player)
|
|
{
|
|
Window *w;
|
|
|
|
w = AllocateWindowDescFront(&_player_stations_desc, player);
|
|
if (w) {
|
|
w->caption_color = (byte)w->window_number;
|
|
w->vscroll.cap = 12;
|
|
}
|
|
}
|
|
|
|
static const Widget _station_view_expanded_widgets[] = {
|
|
{ WWT_TEXTBTN, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
|
|
{ WWT_CAPTION, 14, 11, 236, 0, 13, STR_300A_0, STR_018C_WINDOW_TITLE_DRAG_THIS},
|
|
{ WWT_STICKYBOX, 14, 237, 248, 0, 13, 0x0, STR_STICKY_BUTTON},
|
|
{ WWT_IMGBTN, 14, 0, 237, 14, 65, 0x0, STR_NULL},
|
|
{ WWT_SCROLLBAR, 14, 238, 248, 14, 65, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
|
|
{ WWT_EMPTY, 0, 0, 0, 0, 0, 0x0, STR_NULL},
|
|
{ WWT_IMGBTN, 14, 0, 248, 66, 197, 0x0, STR_NULL},
|
|
{ WWT_PUSHTXTBTN, 14, 0, 63, 198, 209, STR_00E4_LOCATION, STR_3053_CENTER_MAIN_VIEW_ON_STATION},
|
|
{ WWT_PUSHTXTBTN, 14, 64, 128, 198, 209, STR_3033_ACCEPTS, STR_3056_SHOW_LIST_OF_ACCEPTED_CARGO},
|
|
{ WWT_PUSHTXTBTN, 14, 129, 192, 198, 209, STR_0130_RENAME, STR_3055_CHANGE_NAME_OF_STATION},
|
|
{ WWT_PUSHTXTBTN, 14, 193, 206, 198, 209, STR_TRAIN, STR_SCHEDULED_TRAINS_TIP },
|
|
{ WWT_PUSHTXTBTN, 14, 207, 220, 198, 209, STR_LORRY, STR_SCHEDULED_ROAD_VEHICLES_TIP },
|
|
{ WWT_PUSHTXTBTN, 14, 221, 234, 198, 209, STR_PLANE, STR_SCHEDULED_AIRCRAFT_TIP },
|
|
{ WWT_PUSHTXTBTN, 14, 235, 248, 198, 209, STR_SHIP, STR_SCHEDULED_SHIPS_TIP },
|
|
{ WIDGETS_END},
|
|
};
|
|
|
|
static const Widget _station_view_widgets[] = {
|
|
{ WWT_TEXTBTN, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
|
|
{ WWT_CAPTION, 14, 11, 236, 0, 13, STR_300A_0, STR_018C_WINDOW_TITLE_DRAG_THIS},
|
|
{ WWT_STICKYBOX, 14, 237, 248, 0, 13, 0x0, STR_STICKY_BUTTON},
|
|
{ WWT_IMGBTN, 14, 0, 237, 14, 65, 0x0, STR_NULL},
|
|
{ WWT_SCROLLBAR, 14, 238, 248, 14, 65, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
|
|
{ WWT_IMGBTN, 14, 0, 248, 66, 97, 0x0, STR_NULL},
|
|
{ WWT_EMPTY, 0, 0, 0, 0, 0, 0x0, STR_NULL},
|
|
{ WWT_PUSHTXTBTN, 14, 0, 63, 98, 109, STR_00E4_LOCATION, STR_3053_CENTER_MAIN_VIEW_ON_STATION},
|
|
{ WWT_PUSHTXTBTN, 14, 64, 128, 98, 109, STR_3032_RATINGS, STR_3054_SHOW_STATION_RATINGS},
|
|
{ WWT_PUSHTXTBTN, 14, 129, 192, 98, 109, STR_0130_RENAME, STR_3055_CHANGE_NAME_OF_STATION},
|
|
{ WWT_PUSHTXTBTN, 14, 193, 206, 98, 109, STR_TRAIN, STR_SCHEDULED_TRAINS_TIP },
|
|
{ WWT_PUSHTXTBTN, 14, 207, 220, 98, 109, STR_LORRY, STR_SCHEDULED_ROAD_VEHICLES_TIP },
|
|
{ WWT_PUSHTXTBTN, 14, 221, 234, 98, 109, STR_PLANE, STR_SCHEDULED_AIRCRAFT_TIP },
|
|
{ WWT_PUSHTXTBTN, 14, 235, 248, 98, 109, STR_SHIP, STR_SCHEDULED_SHIPS_TIP },
|
|
{ WIDGETS_END},
|
|
};
|
|
|
|
static void DrawStationViewWindow(Window *w)
|
|
{
|
|
Station *st;
|
|
int i;
|
|
int num;
|
|
int x,y;
|
|
int pos;
|
|
StringID str;
|
|
byte station_id;
|
|
byte *b;
|
|
|
|
|
|
station_id = (byte)w->window_number;
|
|
|
|
st = DEREF_STATION(w->window_number);
|
|
|
|
num = 1;
|
|
for(i=0; i!=NUM_CARGO; i++) {
|
|
if ((st->goods[i].waiting_acceptance & 0xFFF) != 0) {
|
|
num++;
|
|
if (st->goods[i].enroute_from != station_id)
|
|
num++;
|
|
}
|
|
}
|
|
SetVScrollCount(w, num);
|
|
|
|
w->disabled_state = st->owner == _local_player ? 0 : (1 << 9);
|
|
|
|
if (!(st->facilities & FACIL_TRAIN)) SETBIT(w->disabled_state, 10);
|
|
if (!(st->facilities & FACIL_TRUCK_STOP) &&
|
|
!(st->facilities & FACIL_BUS_STOP)) SETBIT(w->disabled_state, 11);
|
|
if (!(st->facilities & FACIL_AIRPORT)) SETBIT(w->disabled_state, 12);
|
|
if (!(st->facilities & FACIL_DOCK)) SETBIT(w->disabled_state, 13);
|
|
|
|
SetDParam(0, st->index);
|
|
SetDParam(1, st->facilities);
|
|
DrawWindowWidgets(w);
|
|
|
|
x = 2;
|
|
y = 15;
|
|
pos = w->vscroll.pos;
|
|
|
|
if (--pos < 0) {
|
|
str = STR_00D0_NOTHING;
|
|
for(i=0; i!=NUM_CARGO; i++)
|
|
if (st->goods[i].waiting_acceptance & 0xFFF)
|
|
str = STR_EMPTY;
|
|
SetDParam(0, str);
|
|
DrawString(x, y, STR_0008_WAITING, 0);
|
|
y += 10;
|
|
}
|
|
|
|
i = 0;
|
|
do {
|
|
uint waiting = (st->goods[i].waiting_acceptance & 0xFFF);
|
|
if (waiting == 0)
|
|
continue;
|
|
|
|
num = (waiting + 5) / 10;
|
|
if (num != 0) {
|
|
int cur_x = x;
|
|
num = min(num, 23);
|
|
do {
|
|
DrawSprite(_cargoc.sprites[i], cur_x, y);
|
|
cur_x += 10;
|
|
} while (--num);
|
|
}
|
|
|
|
if ( st->goods[i].enroute_from == station_id) {
|
|
if (--pos < 0) {
|
|
SetDParam(1, waiting);
|
|
SetDParam(0, _cargoc.names_long_s[i] + (waiting==1 ? 0 : 32));
|
|
DrawStringRightAligned(x + 234, y, STR_0009, 0);
|
|
y += 10;
|
|
}
|
|
} else {
|
|
/* enroute */
|
|
if (--pos < 0) {
|
|
SetDParam(1, waiting);
|
|
SetDParam(0, _cargoc.names_long_s[i] + (waiting==1 ? 0 : 32));
|
|
DrawStringRightAligned(x + 234, y, STR_000A_EN_ROUTE_FROM, 0);
|
|
y += 10;
|
|
}
|
|
|
|
if (pos > -5 && --pos < 0) {
|
|
SetDParam(0, st->goods[i].enroute_from);
|
|
DrawStringRightAligned(x + 234, y, STR_000B, 0);
|
|
y += 10;
|
|
}
|
|
}
|
|
} while (pos > -5 && ++i != 12);
|
|
|
|
if (w->widget == _station_view_widgets) {
|
|
b = _userstring;
|
|
b[0] = 0x81;
|
|
b[1] = STR_000C_ACCEPTS;
|
|
b[2] = STR_000C_ACCEPTS >> 8;
|
|
b += 3;
|
|
|
|
for(i=0; i!=NUM_CARGO; i++) {
|
|
if ((b - (byte *) &_userstring) + 5 > USERSTRING_LEN - 1)
|
|
break;
|
|
if (st->goods[i].waiting_acceptance & 0x8000) {
|
|
b[0] = 0x81;
|
|
WRITE_LE_UINT16(b+1, _cargoc.names_s[i]);
|
|
WRITE_LE_UINT16(b+3, 0x202C);
|
|
b += 5;
|
|
}
|
|
}
|
|
|
|
if (b == (byte*)&_userstring[3]) {
|
|
b[0] = 0x81;
|
|
b[1] = STR_00D0_NOTHING;
|
|
b[2] = STR_00D0_NOTHING >> 8;
|
|
b[3] = 0;
|
|
} else {
|
|
b[-2] = 0;
|
|
}
|
|
|
|
DrawStringMultiLine(2, 67, STR_SPEC_USERSTRING, 245);
|
|
} else {
|
|
|
|
DrawString(2, 67, STR_3034_LOCAL_RATING_OF_TRANSPORT, 0);
|
|
|
|
y = 77;
|
|
for(i=0; i!=NUM_CARGO; i++) {
|
|
if (st->goods[i].enroute_from != 0xFF) {
|
|
SetDParam(0, _cargoc.names_s[i]);
|
|
SetDParam(2, st->goods[i].rating * 101 >> 8);
|
|
SetDParam(1, STR_3035_APPALLING + (st->goods[i].rating >> 5));
|
|
DrawString(8, y, STR_303D, 0);
|
|
y += 10;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static void StationViewWndProc(Window *w, WindowEvent *e)
|
|
{
|
|
switch(e->event) {
|
|
case WE_PAINT:
|
|
DrawStationViewWindow(w);
|
|
break;
|
|
|
|
case WE_CLICK:
|
|
switch(e->click.widget) {
|
|
case 7:
|
|
ScrollMainWindowToTile(DEREF_STATION(w->window_number)->xy);
|
|
break;
|
|
|
|
case 8:
|
|
SetWindowDirty(w);
|
|
|
|
/* toggle height/widget set */
|
|
w->height ^= (210 ^ 110);
|
|
*(uint32*)&w->widget ^= (uint32)_station_view_expanded_widgets ^ (uint32)_station_view_widgets;
|
|
|
|
SetWindowDirty(w);
|
|
break;
|
|
|
|
case 9: {
|
|
Station *st = DEREF_STATION(w->window_number);
|
|
SetDParam(0, st->town->townnametype);
|
|
SetDParam(1, st->town->townnameparts);
|
|
ShowQueryString(st->string_id, STR_3030_RENAME_STATION_LOADING, 31, 180, w->window_class, w->window_number);
|
|
} break;
|
|
|
|
case 10: {
|
|
const Station *st = DEREF_STATION(w->window_number);
|
|
ShowPlayerTrains(st->owner, w->window_number);
|
|
break;
|
|
}
|
|
|
|
case 11: {
|
|
const Station *st = DEREF_STATION(w->window_number);
|
|
ShowPlayerRoadVehicles(st->owner, w->window_number);
|
|
break;
|
|
}
|
|
|
|
case 12: {
|
|
const Station *st = DEREF_STATION(w->window_number);
|
|
ShowPlayerAircraft(st->owner, w->window_number);
|
|
break;
|
|
}
|
|
|
|
case 13: {
|
|
const Station *st = DEREF_STATION(w->window_number);
|
|
ShowPlayerShips(st->owner, w->window_number);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case WE_ON_EDIT_TEXT: {
|
|
Station *st;
|
|
byte *b = e->edittext.str;
|
|
if (*b == 0)
|
|
return;
|
|
memcpy(_decode_parameters, b, 32);
|
|
|
|
st = DEREF_STATION(w->window_number);
|
|
DoCommandP(st->xy, w->window_number, 0, NULL, CMD_RENAME_STATION | CMD_MSG(STR_3031_CAN_T_RENAME_STATION));
|
|
} break;
|
|
|
|
case WE_DESTROY: {
|
|
WindowNumber wno =
|
|
(w->window_number << 16) | DEREF_STATION(w->window_number)->owner;
|
|
|
|
DeleteWindowById(WC_TRAINS_LIST, wno);
|
|
DeleteWindowById(WC_ROADVEH_LIST, wno);
|
|
DeleteWindowById(WC_SHIPS_LIST, wno);
|
|
DeleteWindowById(WC_AIRCRAFT_LIST, wno);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static const WindowDesc _station_view_desc = {
|
|
-1, -1, 249, 110,
|
|
WC_STATION_VIEW,0,
|
|
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON,
|
|
_station_view_widgets,
|
|
StationViewWndProc
|
|
};
|
|
|
|
void ShowStationViewWindow(int station)
|
|
{
|
|
Window *w;
|
|
byte color;
|
|
|
|
w = AllocateWindowDescFront(&_station_view_desc, station);
|
|
if (w) {
|
|
color = DEREF_STATION(w->window_number)->owner;
|
|
if (color != 0x10)
|
|
w->caption_color = color;
|
|
w->vscroll.cap = 5;
|
|
}
|
|
}
|