📄 window.java
字号:
import javax.microedition.lcdui.*;
public class Window {
// color related hard coded!
// change it in the 'init' stage, not in the middle of computation
// or simply change the hard coded value _here_
public static int bg = 0xff00ff; // background color
public static int fg = 0xfff7ae; // foreground (text)
public static int selfg = 0xff8a5d; // selected foreground
public static int selbg = 0xfff7ae; // selected back (follow Windows)
public static int borderColor = 0xffba5d; // windows border (outter?)
public static int scrollColor = 0xffffff; // 0xd6d3ce;
public int numChoices = 0;
int[] choiceHeight = null;
int[] choiceOffset = null;
// For scroll calculation
// definition:
// if choiceText != null then show it, as drawMenu
public String[] choiceText = null;
// The position / dimension of the Choices/Message Windows
// Default setting
//
public int menuWidth = Common.SCREEN_HALF_WIDTH;
public int menuHeight ; // = Common.SCREEN_HEIGHT * 4 / 5;
public int menux = (MainGame.screen_width - menuWidth) >> 1;
public int menuy; // = 2; // (Common.SCREEN_HEIGHT - menuHeight) >> 1;
// not included the window frame and frame content space
final int SCROLL_SHIFT = 3; // constant for scrolling
final int SCROLL_WIDTH = 2;
public int selectedChoice = 0;
public int choiceWinOffset = 0;
private int totalChoicesHeight = 0; // Total sum of the choice height
private final int ANCHOR = Graphics.LEFT | Graphics.TOP;
/**
*
* Features:
*
* - display "choices[]" when it is non-null
* - display "message[]" when it is non-null
* - auto adjust the menuHeight when the total heights are less.
* - auto adjust the menux, menuy, menuWidth, menuHeight
* - if you use -1 (default), Set _ALL_ -1
* - partially default and partially manual value may have unexpected
* result.
*
* ------- menu related:
* @param _menux
* @param _menuy
* @param _menuWidth
* @param _menuHeight
* @param choices
* @param qty
*/
public Window(int _menux, int _menuy, int _menuWidth, int _menuHeight,
String[] choices) {
// setup default for message=null and non-null cases
menuHeight = (Common.SCREEN_HEIGHT * 4) / 5;
menuy = (Common.SCREEN_HEIGHT - menuHeight) >> 1;
// init the value:
if (_menuWidth >= 0)
menuWidth = _menuWidth;
if (_menuHeight >= 0)
menuHeight = _menuHeight;
if (_menux >= 0)
menux = _menux;
else
menux = (MainGame.screen_width - menuWidth) >> 1;
if (_menuy >= 0)
menuy = _menuy;
// Setting the choices
setChoices(choices);
int totalHeight = 0;
for (int i = 0; i < numChoices; i++)
totalHeight += choiceHeight[i];
final int BORDER_H = 0; // 1 for experimental
if (menuHeight > totalHeight + BORDER_H)
menuHeight = totalHeight + BORDER_H; //
}
/**
* init the choice related values
* ---------------------
* input: choices are not yet splitted.
* assumption: menuWidth is already setup,
* splitting depends on menuWidth
*
* output: (implicit value change)
* - numChoice = total number of choices
* - String choiceText[numChoice][NUM_OF_LINES_FOR_EACH_CHOICE]
* - int choiceOffset[numChoice] // for ease of calculation
* - int choiceHeight[numChoice] - height of each choice
* - byte choiceQuantity[]
*
* -----------------------
* Note: implicit use "menuWidth", from constructor
*
* @param choices
* @param quantity
*/
public void setChoices(String[] choices) {
// simple null check
if (choices == null) {
choiceText = null; // must set this null to hide choice
return;
}
// Set the number of choices we have
// numChoices is global
numChoices = choices.length;
choiceOffset = new int[numChoices];
// Definition:
// choiceOffset[i] = the distance between choice[0] to choice[i]
// Not affected by the display window (Runtime)
choiceHeight = new int[numChoices];
choiceText = choices;
// Update the choiceHeight / choiceOffset
int offsetToTop = 0;
totalChoicesHeight = 0;
for(int i = 0; i < numChoices;i++){
// store the choice heights
choiceHeight[i] = Common.FONT_LINE_H;
// store the choiceOffset
choiceOffset[i] = offsetToTop;
offsetToTop += choiceHeight[i];
//System.out.println(""+choiceHeight[i]);
}
totalChoicesHeight = offsetToTop;
// initial offset should be zero
choiceWinOffset = 0;
}
public void draw(Graphics g) {
// For Auto-calculating Message position
// int spacing = 2;
// int mx = 2;
// int my = menuy + menuHeight + 2 + spacing;
// int mHeight = Common.SCREEN_HEIGHT - my - 2;
// int mWidth = Common.SCREEN_WIDTH - 4;
if (choiceText != null) {
drawMenu(g, menux, menuy, menuWidth, menuHeight);
}
}
/**
* depends on instance variable:
* - choiceText, choiceHeight, choiceOffset, totalChoicesHeight
* // Set by setChoices
* - selectedChoice, choiceWinOffset
* // Calculated when the choice is changed.
*
* Actual Menu
*
* |------ menuStarty = y-Offset
* v__________
* | Choice 1 | ^---- Offset from menu to display window (x,y)
* |__________| | Display window
* | Choice 2 | v____w_____
* |__________| | |
* | | | | <-- h
* | Choice 3 | |__________|
* |__________|
* | Choice 4 |
* |__________|
*
*
*
* @param g - Graphics handle
* @param x - Top Left position (x-coordinate)
* @param y - Top Left position (y-coordinate)
* @param w - Width of the menu window
* @param h - Height of the menu window
* @param offset - the offset of the display windows apart from
* the menu real top
* @param list
*/
public void drawMenu(Graphics g, int x, int y, int width, int height) {
g.setClip(0, 0, Common.SCREEN_WIDTH, Common.SCREEN_HEIGHT);
drawWindow(g, x - 1, y - 2, width + 1, height + 1);
// Clip to draw the content
// y+1 and height-2 is to keep the highlight bar having 1 space
// apart to the frame border
g.setClip(x, y, width, height - 1);
// Menu Calculate
// starty + offset = y (the y of visual window)
int choiceTop = y - choiceWinOffset ;
int offsetBottom = choiceWinOffset + height;
// Adjustment
// Align-left
int textx = x + 4;
// Menu Fore-ground color
g.setColor(fg);
int currentOffset = 0;
int topOffset = -1;
int bottomOffset = -1;
// this setFont is necessary.
// to uplift this, need to change this function to private,
// put the g.setFont in draw(), then we can remove setFont in
// drawMessage also.
g.setFont(MainGame.font);
for (int i = 0; i < numChoices; i++) {
int myHeight = choiceHeight[i];
// Draw the choices
if (i == selectedChoice) {
g.setColor(selbg);
g.fillRect(x + 1, choiceTop, width - 2, myHeight);
// draw the select bar
// -2 to leave a space between the highlight
// and the border
g.setColor(selfg);
} else {
g.setColor(fg);
}
// Drawing the choice text
g.drawString(choiceText[i], textx, choiceTop, ANCHOR);
choiceTop += Common.FONT_LINE_H;
// Reset to the original fg
if (i == selectedChoice) {
g.setColor(fg);
}
// Update the offset and next drawing position
currentOffset += myHeight;
}
if (height < totalChoicesHeight) {
drawMenuScroll(g, x, y-1, width, height);
}
}
public void drawMenuScroll(Graphics g, int parentx, int parenty,
int parentWidth, int parentHeight) {
// x,y is the TOP_LEFT position of the scroll-bar
// width, height is the width x height of the scroll-bar
// The above pos, size is not include the border of the scroll
// Preventation of Divide by Zero
if (totalChoicesHeight == 0) {
//#ifdef DEBUG
//# System.out.println("DEBUG: totalChoicesLength = 0, "
//# + " unexpected. probably no choice is set.");
//#endif
return;
}
int spacing = 0;
// Derive the scroll bar content x,y,width,height
int x = parentx + parentWidth + 1 + spacing;
// just besides the parent border
int y = parenty; // Same as parent
int width = SCROLL_WIDTH;
int height = parentHeight;
// set clip (REMARK: the left-most black border not in-clip
g.setClip(x - 1, y - 2, width + 3, height + 4);
// The border (same as drawMenu)
drawWindow(g, x - 1, y - 1, width + 1, height + 1);
// Set the clip to prevent draw too much
g.setClip(x, y, width, height);
// why do "*" before "/", for integer, if value1/value2
// 0.xxx value, it will treat as zero and cause the multiply
// afterward become zero.
int scrollOffset = (choiceWinOffset * height) / totalChoicesHeight;
int scrollLength = parentHeight * height / totalChoicesHeight + 1;
int barStarty = y + scrollOffset;
// Comment the follow if wanna to make the bar same color
// as the menu window color
g.setColor(scrollColor); // grey
g.fillRect(x, barStarty, width, scrollLength);
}
/**
* called when key press is UP. selectedChoice may or "may not" be
* changed!
*
* when to change?
* -> selectedChoice is not the first item
* -> AND: top of the selectedChoice is larger than or equal to the top of window
*
* when NOT to change?
* -> selectedChoice is the first item
* -> OR: top of the selectedChoice is less than the top of window
*
*/
public void keyUp() {
// only applicable when choice is NOT null
if (choiceText == null)
return;
if (selectedChoice <= 0) {
// Go to the last choice and align it to the bottom
selectedChoice = numChoices - 1;
if (numChoices > 1) {
choiceWinOffset = choiceOffset[selectedChoice]
+ choiceHeight[selectedChoice] - menuHeight;
}
return;
}
if (choiceOffset[selectedChoice - 1] < choiceWinOffset) {
// case 2.2: next thin choice is out of menu sight
// align top
choiceWinOffset = choiceOffset[selectedChoice - 1];
}
selectedChoice--;
}
/**
* Called when key press is down, selectedChoice "may" be changed,
* may not be changed.
* When to change?
* -> bottom of the selectedChoice is less than the bottom of window
* (no need to scroll)
* -> AND: selectedChoice is not the last one.
*
* When not to change?
* -> bottom of selectedChoice > bottom of window, scroll down N pixel
* (scroll case, big choice case)
* -> OR selectedChoice is the last one
*
* _no_ cyclic selection (at least for now)
*/
public void keyDown() {
// only applicable when choice is NOT null
if (choiceText == null)
return;
// NOTES!! The order is important
// First check the FAT choices case, then the LAST choice
// or else the LAST & FAT choices can't scroll down
// LAST choice handling
// if (selectedChoice >= numChoices-1) return ; // last choice case
if (selectedChoice >= numChoices - 1) {
// Go to the first choice
selectedChoice = 0;
choiceWinOffset = choiceOffset[selectedChoice];
return;
}
// logic:
if (choiceOffset[selectedChoice + 1]
+ choiceHeight[selectedChoice + 1] > choiceWinOffset
+ menuHeight) {
// align bottom
choiceWinOffset = choiceOffset[selectedChoice + 1]
+ choiceHeight[selectedChoice + 1] - menuHeight;
}
// last logic:
selectedChoice++;
}
// drawWindow frame:
// 1. draw a white border (inner) from x, y, with size: width, height
// 2. draw a big background frame from x-1, y-1 with size width/height + 3
//
// main color is the background color
public static void drawWindow(Graphics g, int x, int y, int width,
int height) {
// 2. draw a larger background,
g.setColor(bg); // bg is now static, constant
g.fillRect(x - 1, y - 1, width + 3, height + 3);
// ORDER is important: 2 -> 1
// 1. draw a white border, which is 1 pixel inner than the black border
g.setColor(borderColor);
g.drawRect(x, y, width, height);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -